5

在 C# 中进行线程同步时,我是否应该在读取值或只是更改它时锁定一个对象?

例如我有 Queue<T> 对象。我应该在执行 Enqueue 和 Dequeue 时锁定它,还是在检查 Count 等值时也应该锁定它?

4

4 回答 4

3

来自 MSDN:

一个 Queue<(Of <(T>)>) 可以同时支持多个读取器,只要不修改集合即可。即便如此,通过集合枚举本质上不是线程安全的过程。为了保证枚举过程中的线程安全,可以在整个枚举过程中锁定集合。要允许集合被多个线程访问以进行读写,您必须实现自己的同步。

您应该确保在项目排队时没有阅读器处于活动状态(锁定可能是个好主意)。

查看反射器中的计数显示来自私有字段的读取。这可能没问题,具体取决于您对值的处理方式。这意味着你不应该做这样的事情(没有适当的锁定):

if(queue.Count > 0)
    queue.Dequeue();
于 2009-01-10T15:49:12.450 回答
2

取决于你想用锁做什么。通常这种锁定需要读写器锁定机制。

读者/作者锁定意味着读者共享一个锁,因此您可以让多个读者同时读取集合,但要写入,您应该获取排他锁。

于 2009-01-10T15:45:09.243 回答
1

如果你不锁定它,你可能会得到一个较旧的值。可能会出现竞争条件,即执行写入操作会更改 Count,但您将获得更改之前的值。例如,如果队列只有一个项目,并且一个线程调用 dequeue,另一个线程可能会读取计数,发现它仍然是 1,然后再次调用 dequeue。在授予锁定之前不会完成第二次调用,但那时队列实际上是空的。

于 2009-01-10T15:48:44.867 回答
0

CLR 保证原子读取最大处理器宽度的值。因此,如果您在 32 位上运行,读取ints 将是原子的。如果您在 64 位机器上运行,读取longs 将是原子的。因此,如果Count是,Int32则无需锁定。

这篇文章与您的问题有关。

于 2009-01-10T15:46:44.763 回答