这段代码是线程安全的吗?

时间:2010-04-04 15:59:52

标签: c# thread-safety locking

我有一个有几个属性的课程。在每次更新值时,都会调用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);
        }
    }
}

这个设计是否是线程安全的?

(顺便说一句,如果您能想到更合适的标题,请随时编辑。)

我认为它是线程安全的。如果在多个线程上更改了属性,则值将按随机顺序设置,原子存储将以随机顺序发生,但最终,每个属性都将具有其最新值,并且最后会发生原子存储,确保文件是最新的。

澄清:不会经常设置属性,但可以同时设置它们。重要的是大部分时间都有一个有效的文件。

如果某个线程要根据属性值更改属性,则必须锁定整个对象以与其他线程同步。这与枚举List上的锁定基本相同,并不是此类的责任。

6 个答案:

答案 0 :(得分:5)

这取决于你在不同线程上调用的内容。

如果一次在不同的线程上设置属性,则它不是线程安全的,因为属性在序列化时可能会发生变化。

答案 1 :(得分:1)

没有

如果你想同步属性theirself,这段代码不是线程安全的,因为'lock'不在_Prop1值上,而只在_Ser上。实际上,当一个线程进入该属性时,该属性可以由另一个线程设置。

即使是序列化过程,_Ser访问可以被执行中的其他线程更改的属性(当_Ser正在运行时,另一个线程集Prop1)。

此代码实际上不允许多个线程使用XmlSerialize _Ser对象。如果它是您想要的...


答案主要取决于你想得到什么。

答案 2 :(得分:1)

没有足够的代码来拨打电话。但是可以肯定的是,如果您没有序列化对文件的写访问权,那么将不会发生任何好事。如果第一个线程仍在忙于写入文件,则分配属性的第二个线程将在IOException上进行炸弹。

像这样的细粒度锁定通常是个问题。客户端代码可能忙于更改类的多个属性。如果引发异常,您将获得部分更新,从而生成包含无效序列化状态的文件,并且在读取时可能会造成麻烦。你需要像BeginUpdate(),EndUpdate()对这样的东西。

答案 3 :(得分:0)

我建议使用某种Mutex来确保数据仅在特定点进行序列化,它可以在更新更改或即将更改时执行。

以下链接将带您进入MSDN网站上的一个简单示例,该示例应该有希望为您演示:

Mutex Example

答案 4 :(得分:0)

如果可以从多个主题调用Prop1属性,请创建_Prop1字段volatile

private volatile int _Prop1;

来自MSDN,

  

volatile 关键字表示a   字段可能会被多个修改   正在执行的线程   时间。声明的字段    volatile 不受编译器限制   假设访问的优化   单线程。这确保了   最新的价值存在于   在任何时候都在这个领域。

考虑一下好的做法。它不会使您发布的代码线程安全,因为正如其他人所说,在序列化类时,_Prop1的值可以被另一个线程更改。但是,如果您有一个能够由多个线程读取和写入的字段,则将该字段标记为volatile可确保您的代码看到最新值。

答案 5 :(得分:0)

不是线程安全的,除非属性类型是原子的。

简单的例子,带有线程A和B.

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

数据的完整性可能会受到影响。即使类型与Int64一样简单,理论上也可能出现问题。

在设置器中放置另一个lock(_Ser)会有所帮助。