为什么在这里使用锁

本文关键字:在这里 为什么 | 更新日期: 2023-09-27 18:34:46

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

我知道如果 ProgressStatus 类是可变的,您将需要锁定读取和写入它,因为如果一个线程在更新 PercentComplete 和 StatusMessage 字段之间被另一个读取状态的线程抢占,第二个线程可能会获得这些字段无效值对。(100% 完成/"操作进行中..."(

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

为什么在这里使用锁

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

可能导致"过时数据",读取代码可以缓存它并且只能看到旧值。

lock的这种用法是典型的,它从lock的副作用中获利:它有一个隐含的记忆屏障,这阻止了看到旧副本。你更通常会看到一个volatile ProgressStatus _status;volatile也有它的问题。

您是对的,实际的读取和写入操作在这里根本不需要锁定(访问引用是原子的(。

例如

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

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

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

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