我有以下代码:
public class Info
{
public int Data { get; set; }
}
public class Updater
{
private static readonly object lockObject = new object();
private Info myInfo= new Info();
public Info MyInfo
{
get
{
lock (lockObject)
{
return myInfo;
}
}
}
public void UpdateInfo()
{
lock (lockObject)
{
myInfo.Data = ReadFromExternalDevice();
}
}
}
我有一个Updater
实例,可以从两个不同的线程访问。
Updater updater = new Updater();
线程#1定期调用UpdateInfo()
。
updater.UpdateInfo();
线程#2定期从Data
属性的Info
属性中读取。
int latestData = updater.MyInfo.Data;
以上代码是否接近线程安全?
答案 0 :(得分:2)
想象一下
MyInfo
(离开锁定return myInfo;
后)MyInfo
属性MyInfo
MyInfo
(部分更改!)属性在这种情况下,代码不线程安全。即使MyInfo
只有一个int
字段,也不是线程安全:
MyInfo info = Updater.Info;
Console.Write(info.Data);
// Here 2nd thread changes the info
Console.Write(info.Data);
典型实施使用ReaderWriterLockSlim
https://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim(v=vs.110).aspx
EnterReadLock()
时将(克隆)MyInfo
读入本地变量(或使用MyInfo
执行所有必需的过程),然后{ {1}} ExitReadLock()
时写入,然后EnterWriteLock()
答案 1 :(得分:1)
如果您只关心读取 Data
属性,那么这个实现就是......让我们说......线程足够安全。
对于32位值的读写操作在C#中是 atomic ,因此updater.MyInfo.Data
中任何时候都没有奇怪的中间值。如果您有更新的更复杂的属性,则不再适用。线程2可能只是部分更新了这些属性,而线程1仍然在相同的MyInfo
上阅读。
但如果您尝试执行类似
的操作if (updater.MyInfo.Data == 5)
updater.MyInfo.Data = 7;
在不同的线程中,不再保证按预期运行。由于另一个线程可能在检查和分配之间更改了Data
的值。
您可能需要查看Interlocked.Exchange
以获取更新变量的线程安全方法。