简体   繁体   English

此代码是线程安全的吗?

[英]Is this code thread-safe?

I've got a class with several properties. 我有一堂课,有几个属性。 On every value update, a Store method is called which stores all fields (in a file). 每次值更新时,都会调用一个Store方法,该方法将所有字段存储在一个文件中。

private int _Prop1;
public int Prop1 {
    get {
        return _Prop1;
    }
    set {
        _Prop1 = value;
        Store();
    }
}

// more similar properties here...

private XmlSerializer _Ser = new ...;
private void Store()
{
    lock (_Ser) {
        using (FileStream fs = new ...) {
            _Ser.Serialize (fs, this);
        }
    }
}

Is this design thread-safe? 这个设计是线程安全的吗?

(Btw, if you can think of a more appropriate caption, feel free to edit.) (顺便说一句,如果您能想到一个更合适的标题,请随时进行编辑。)

I think it is thread safe. 我认为这是线程安全的。 If properties are changed on multiple threads, the values will be set in random order, atomic Stores will happen in a random order, but in the end, every property will have its latest value, and at the very end, an atomic Store happens, ensuring that the file is up-to-date. 如果在多个线程上更改属性,则将以随机顺序设置值,原子存储将以随机顺序发生,但是最后,每个属性将具有其最新值,最后,原子存储发生,确保文件是最新的。

Clarification: The properties will not be set very often, but they may be set at the same time. 说明:这些属性不会经常设置,但可以同时设置。 What matters is having a valid file most of the time. 重要的是大多数时候都有一个有效的文件。

If a thread is going to change a property with regards to a property value, it has to lock on the whole object to sync with other threads. 如果线程要更改有关属性值的属性,则它必须锁定整个对象才能与其他线程同步。 That's basically the same as with locking on a List on enumeration and is not a responsibility of this class. 基本上与锁定枚举时的List相同,这不是此类的责任。

It depends what you're calling on different threads. 这取决于您在不同线程上调用的内容。

If you set properties on different threads at once, it isn't thread-safe, because the properties can change while they're being serialized. 如果您一次在不同的线程上设置属性,则它不是线程安全的,因为属性在序列化时可能会更改。

No. 没有。

In the case you want to synchronize the properties theirself, this code is not thread safe, since the 'lock' is not on the _Prop1 value, but only on _Ser. 如果您要自己同步属性,则此代码不是线程安全的,因为“锁”不在_Prop1值上,而仅在_Ser上。 Indeed when a thread is gettin the property, the property could be set by another thread. 实际上,当一个线程成为该属性时,该属性可以由另一个线程设置。

Even the serialization process, _Ser access to properties which can be changed by other threads in execution (while _Ser is running, another thread set Prop1). 即使是序列化过程,_Ser也可以访问其他执行中的线程可以更改的属性(在_Ser运行时,另一个线程设置为Prop1)。

This code actually disallow the use of the XmlSerialize _Ser object by multiple threads. 这段代码实际上禁止多个线程使用XmlSerialize _Ser对象。 If it is what you want to get... 如果这是您想要得到的...


The answer depends essentially on what you want to get. 答案基本上取决于您想要获得什么。

There's not enough code to make the call. 没有足够的代码来拨打电话。 But sure, nothing good is going to happen if you don't serialize write access to the file. 但是可以肯定的是,如果不序列化对文件的写访问,将不会有任何好处。 The 2nd thread that assigns the property is going to bomb on an IOException if the 1st thread is still busy writing the file. 如果第一个线程仍在忙于写入文件,则分配该属性的第二个线程将在IOException上轰炸。

Fine-grained locking like this is usually a problem. 像这样的细粒度锁定通常是一个问题。 The client code could be busy changing more than one property of the class. 客户端代码可能忙于更改类的多个属性。 You'll get a partial update if an exception is raised, producing a file that contains serialized state that is invalid and may cause trouble when it is read. 如果引发异常,您将得到部分更新,生成的文件包含无效的序列化状态,并且在读取时可能会引起麻烦。 You'll need something like a BeginUpdate(), EndUpdate() pair. 您将需要类似BeginUpdate(),EndUpdate()对的东西。

I would suggest using some sort of Mutex to ensure the data is only serialized at a particular point, it could do it just as the update changes or is about to change. 我建议使用某种互斥锁来确保仅在特定点对数据进行序列化,这可以在更新更改或即将更改时执行。

The following link takes you to a simple example on the MSDN website that should hopefully demonstrate it for you: 以下链接将您带到MSDN网站上的一个简单示例,希望可以为您演示该示例:

Mutex Example 互斥体示例

If the Prop1 property can be called from multiple threads, make the _Prop1 field volatile . 如果可以从多个线程调用Prop1属性,则使_Prop1字段为volatile

private volatile int _Prop1;

From MSDN, 从MSDN,

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. volatile关键字指示一个字段可能被同时执行的多个线程修改。 Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. 声明为易失性的字段不受假定单个线程访问的编译器优化的约束。 This ensures that the most up-to-date value is present in the field at all times. 这样可以确保始终在字段中显示最新值。

Consider it good practice. 认为这是一种好习惯。 It's not going to make the code you posted thread safe because, as others have said, while the class is being serialized, the value of _Prop1 can be changed by another thread. 这样做不会使您发布的代码的线程安全,因为,正如其他人所说的那样,当类被序列化时, _Prop1的值可以由另一个线程更改。 Still, if you have a field that is capable of being read and written by multiple threads, marking the field as volatile guarantees that your code sees the most current value. 尽管如此,如果您拥有一个可以被多个线程读取和写入的字段,则将该字段标记为volatile可以确保您的代码看到最新的值。

Not thread safe, unless the property type is atomic. 除非属性类型是原子的,否则不是线程安全的。

Simple example, with threads A and B. 简单示例,线程A和B。

A: Prop1 = foo
A: Store()
A:    ... store saves foo.Var1
B: Prop1 = bar
A:    ... store saves bar.Var2 (instead of foo.Var2)

The integrity of the data is possibly compromised. 数据的完整性可能会受到损害。 Even with types as simple as Int64, problems can occur in theory. 即使使用Int64这样简单的类型,理论上也会出现问题。

Putting another lock(_Ser) within the setter would help. 在设置器中放置另一个lock(_Ser)将有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM