我的一个类有一个Guid类型的属性。此属性可以由多个线程同时读取和写入。我的印象是对Guid的读写不是原子的,因此我应该锁定它们。
我选择这样做:
public Guid TestKey
{
get
{
lock (_testKeyLock)
{
return _testKey;
}
}
set
{
lock (_testKeyLock)
{
_testKey = value;
}
}
}
(在我的课程中,对Guid的所有访问也是通过该属性完成的,而不是直接访问_testKey。)
我有两个问题:
(1)是否真的有必要像这样锁定Guid以防止撕裂读数? (我很确定它是。)
(2)这是一种合理的锁定方式吗?或者我需要像下面这样做:
get
{
Guid result;
lock (_testKeyLock)
{
result = _testKey;
}
return result;
}
[编辑]本文确认Guids将遭受撕裂的阅读:http://msdn.microsoft.com/en-us/magazine/jj863136.aspx
答案 0 :(得分:8)
1:是的;如果你有一个线程读数和一个写入,以防止撕裂的价值; Guid
不保证是原子的
2:“喜欢以下”:它们实际上是一样的;在IL级别,您<{>}} / ret
块不能 try
,因此编译器通过引入局部变量来实现您的第一个示例,就像在您的第二个例子。
另一种方法可能是把它包装起来;引用是原子:
catch
不需要锁定,但只需要一小段开销。
答案 1 :(得分:4)
1)是否真的有必要像这样锁定Guid以防止撕裂读数? (我很确定它是。)
是的。
2)这是一种合理的锁定方式吗?
再次:是的。
如果Interlocked
存在Guid
方法,则会更好(更快)。
对于double
(另一个非原子结构),有来自Interlocked
的支持,对于引用则不需要它。
因此,只有Interlocked
不支持的较大结构才需要这种模式。