C#我什么时候需要锁?

时间:2012-09-16 19:16:31

标签: c# multithreading

我已经阅读了一些关于线程安全的内容,但我想了解我需要锁定什么操作。

例如,假设我想要一个线程安全队列/ 如果deqeue操作将返回第一个元素(如果有的话),我何时需要锁定?假设我正在使用条目的抽象链接列表。

是否应该锁定写入操作?还是读书?或两者兼而有之?

希望有人能向我解释或给我一些链接。

6 个答案:

答案 0 :(得分:1)

并发场景中的同步是一个非常广泛的主题。基本上,每当两个或多个线程之间有一些共享状态(计数器,数据结构)并且它们中的至少一个与来自不同线程的读取或另一个突变同时地改变该共享状态时,结果可能是不一致的。在这种情况下,您需要使用某种形式的同步(其中锁是一种风格)。

现在回答你的问题,一个出列队列的典型代码如下(伪代码):

if(queue is not empty) 
    queue.dequeue

可以由多个线程同时执行。虽然一些队列实现在内部同步queue is not empty操作以及queue.dequeue操作,但这还不够,因为执行上述代码的线程可能在检查和实际出队之间中断,所以有些即使检查返回true,线程也可能在到达出队时发现队列为空。需要锁定整个序列:

lock(locker)
{
    if(queue is not empty) 
        queue.dequeue
}

请注意,上述内容可能会被某些数据结构实现为单个线程安全操作,但我只是想在此处提出一点。

答案 1 :(得分:1)

我发现锁定和线程的最佳指南是这个页面(这是我在处理锁定和线程时所咨询的文本):

http://www.albahari.com/threading/

哟想要“锁定和线程安全”这一段,但也读了其余部分,它写得非常好。

答案 2 :(得分:0)

有关基本概述,请参阅MSDN: Thread Synchronization。有关更详细的介绍,我建议您阅读Amazon: Concurrent Programming on Windows

答案 3 :(得分:0)

您需要对非原子操作的对象进行锁定。

将对象添加到列表中 - >非原子

为字节或int赋值 - >原子

答案 4 :(得分:0)

作为最简单的经验法则,所有共享可变数据都需要在您访问时锁定锁。

写作时需要锁定,因为您需要确保没有人同时写入相同的字段。

您需要在读取时锁定,因为另一个线程可能在中途写入数据,因此它可能处于不一致状态。 Inconsistant数据可能会产生错误的输出或崩溃。

锁具有与它们相关的一系列问题,(Google用于“餐饮哲学家”)所以我倾向于尽可能避免使用显式锁。更高级别的构建块,如ConcurrentQueue<>是错误的,但你仍然应该阅读文档。

另一种避免锁定的简单方法是为后台进程制作输入数据的副本。甚至更好,使用不可变输入(无法更改的数据)。

答案 5 :(得分:0)

锁定的基本规则

  • 同时改变同一件事不会飞
  • 阅读正在改变的事物不会飞
  • 同时读同样的东西会飞
  • 同时改变不同的东西可能会飞

锁定需要防止无法飞行的情况。这可以通过多种方式完成。 C#为您提供了很多工具。其中Concurrent<>集合类型如ConcurrentDictionary,ConcurrentQueue等。还有ReaderWriterLockSlim等。

你可能会发现这个免费的.pdf来自microsoft很有用。它被称为“C#Threads编程简介”

http://research.microsoft.com/pubs/70177/tr-2005-68.pdf

这是一个更幽默的接力

http://www.codeproject.com/Articles/114262/6-ways-of-doing-locking-in-NET-Pessimistic-and-opt