为什么这里使用锁?

时间:2014-12-20 22:37:41

标签: c# .net multithreading thread-safety locking

我目前正在阅读Joe Albahari的Threading in C#电子书,有时在他的示例代码中,他使用锁定在我看不到线程安全问题的地方。例如,Here,他锁定了对_status字段的写入和读取,该字段引用了一个不可变对象。

据我所知,如果ProgressStatus类是 mutable ,你需要锁定读取和写入它,因为如果在更新PercentComplete和StatusMessage字段之间预先占用一个线程,另一个线程读取状态,第二个线程可能会获得这些字段的无效值对。 (100%完成/"正在进行中......")

但是由于ProgressStatus是不可变的,因此不会出现这种无效状态。如果Joe删除了这两个锁,可能会出现什么线程安全问题?

2 个答案:

答案 0 :(得分:4)

例如,读者可能永远不会看到_status更新为新值。所有读取可能会折叠成一个物理读取。

另外,我认为你可能会看到部分初始化的对象,如果_status在被引用的对象中的字段之前被提交到内存中。

请注意,此锁定与被引用的对象无关。这是关于保护参考本身。

当其中一个访问是写入时,在多个线程上访问变量是数据争用。各种各样的事情都可能发生。我上面所说的只是例子。

答案 1 :(得分:4)

  

如果Joe删除了这两个锁,可能会出现什么线程安全问题?

它可能会导致“陈旧数据”,读取代码可以缓存它并且只能看到旧值。

lock的这种用法是典型的,它从lock的副作用中获利:它具有隐含的内存屏障,并且可以防止查看旧副本。您通常会看到volatile ProgressStatus _status;,但volatile也有问题。

你是对的,实际的读写操作在这里并不需要锁定(访问是一个原子)。