[英]Is this code thread-safe?
我有一堂课,有几个属性。 每次值更新时,都会调用一个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
相同,这不是此类的责任。
这取决于您在不同线程上调用的内容。
如果您一次在不同的线程上设置属性,则它不是线程安全的,因为属性在序列化时可能会更改。
没有。
如果您要自己同步属性,则此代码不是线程安全的,因为“锁”不在_Prop1值上,而仅在_Ser上。 实际上,当一个线程成为该属性时,该属性可以由另一个线程设置。
即使是序列化过程,_Ser也可以访问其他执行中的线程可以更改的属性(在_Ser运行时,另一个线程设置为Prop1)。
这段代码实际上禁止多个线程使用XmlSerialize _Ser对象。 如果这是您想要得到的...
答案基本上取决于您想要获得什么。
没有足够的代码来拨打电话。 但是可以肯定的是,如果不序列化对文件的写访问,将不会有任何好处。 如果第一个线程仍在忙于写入文件,则分配该属性的第二个线程将在IOException上轰炸。
像这样的细粒度锁定通常是一个问题。 客户端代码可能忙于更改类的多个属性。 如果引发异常,您将得到部分更新,生成的文件包含无效的序列化状态,并且在读取时可能会引起麻烦。 您将需要类似BeginUpdate(),EndUpdate()对的东西。
如果可以从多个线程调用Prop1
属性,则使_Prop1
字段为volatile
。
private volatile int _Prop1;
从MSDN,
volatile关键字指示一个字段可能被同时执行的多个线程修改。 声明为易失性的字段不受假定单个线程访问的编译器优化的约束。 这样可以确保始终在字段中显示最新值。
认为这是一种好习惯。 这样做不会使您发布的代码的线程安全,因为,正如其他人所说的那样,当类被序列化时, _Prop1
的值可以由另一个线程更改。 尽管如此,如果您拥有一个可以被多个线程读取和写入的字段,则将该字段标记为volatile可以确保您的代码看到最新的值。
除非属性类型是原子的,否则不是线程安全的。
简单示例,线程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)
将有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.