有人可以解释之间的区别:
我无法弄明白。在我看来前两个是相同的?
答案 0 :(得分:130)
好问题。我可能错了..让我试试..我的原始答案的修订版#2 ......稍微有点理解。谢谢你让我读到:)
锁定(obj)
监视器
使用锁或监视器对于防止同时执行线程敏感的代码块很有用,但这些结构不允许一个线程将事件传递给另一个。这需要同步事件,这些对象具有两种状态之一,信号和无信号,可用于激活和挂起线程。 Mutex,Semaphores是操作系统级别的概念。例如,使用已命名的互斥锁,您可以跨多个(托管)exes进行同步(确保只有一个应用程序实例在计算机上运行。)
Mutex:
Semaphores (伤害了我的大脑)。
答案 1 :(得分:28)
重新“使用其他.Net同步类” - 您应该了解的其他一些内容:
在CCR / TPL(Parallel Extensions CTP)中还有更多(低开销)锁定结构 - 但是IIRC,这些将在.NET 4.0中提供
答案 2 :(得分:13)
正如ECMA中所述,正如您可以从Reflected方法中看到的那样,lock语句基本上等同于
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
…
}
finally {
System.Threading.Monitor.Exit(obj);
}
从前面提到的例子中我们看到监视器可以锁定对象。
当您需要进程间同步时,Mutexe非常有用,因为它们可以锁定字符串标识符。不同的进程可以使用相同的字符串标识符来获取锁。
信号量就像类固醇上的互斥体,它们通过提供最大的并发访问次数来允许并发访问。达到限制后,信号量开始阻止对资源的任何进一步访问,直到其中一个调用者释放信号量。
答案 3 :(得分:12)
我做了课程& CLR支持DotGNU中的线程,我有一些想法...
除非您需要跨进程锁定,否则应始终避免使用Mutex& amp;信号灯。 .NET中的这些类是Win32 Mutex和Semaphores的包装器,并且相当重要(它们需要上下文切换到内核,这很昂贵 - 特别是如果你的锁没有争用)。
正如其他人所提到的,C#lock语句是Monitor.Enter和Monitor.Exit的编译魔术(在try / finally中存在)。
监视器有一个简单但功能强大的信号/等待机制,Mutexes没有通过Monitor.Pulse / Monitor.Wait方法。 Win32等价物将是通过CreateEvent的事件对象,它实际上也作为WaitHandles存在于.NET中。 Pulse / Wait模型类似于Unix的pthread_signal和pthread_wait,但速度更快,因为在无争议的情况下它们可以完全是用户模式操作。
Monitor.Pulse / Wait很简单易用。在一个线程中,我们锁定一个对象,检查一个标志/状态/属性,如果它不是我们所期望的,请调用Monitor.Wait,它将释放锁并等待直到发送一个脉冲。等待返回时,我们循环返回并再次检查flag / state / property。在另一个线程中,每当我们更改flag / state / property然后调用PulseAll来唤醒任何侦听线程时,我们都会锁定对象。
我们通常希望我们的类是线程安全的,所以我们在代码中加入了锁。但是,通常情况是我们的类只会被一个线程使用。这意味着锁会不必要地减慢我们的代码......这就是CLR中的巧妙优化可以帮助提高性能的地方。
我不确定微软的锁实现,但在DotGNU和Mono中,锁状态标志存储在每个对象的标头中。 .NET(和Java)中的每个对象都可以成为一个锁,因此每个对象都需要在其标题中支持它。在DotGNU实现中,有一个标志允许您为每个用作锁的对象使用全局哈希表 - 这有利于消除每个对象的4字节开销。这对于内存来说并不是很好(特别是对于没有高度线程化的嵌入式系统)但是性能受到了打击。
Mono和DotGNU都有效地使用互斥锁来执行锁定/等待,但使用自旋锁式compare-and-exchange操作来消除实际执行硬锁的需要,除非确实有必要:
您可以在此处看到如何实施监视器的示例:
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
答案 4 :(得分:9)
锁定在您使用字符串ID标识的任何共享互斥锁上的另一个警告是它将默认为“本地”互斥锁,并且不会在终端服务器环境中的会话之间共享。
使用“Global \”前缀您的字符串标识符,以确保正确控制对共享系统资源的访问。在我意识到这一点之前,我刚刚遇到了一大堆问题,这些问题与SYSTEM系统帐户下运行的服务同步通信。
答案 5 :(得分:5)
如果可以的话,我会尽量避免“锁定()”,“互斥”和“监视”......
在.NET 4中查看新命名空间System.Collections.Concurrent 它有一些很好的线程安全的集合类
http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx
ConcurrentDictionary摇滚!我不再手动锁定了!
答案 6 :(得分:-2)
在大多数情况下,您不应使用锁(=监视器)或互斥锁/信号灯。它们都阻塞了当前线程。
您绝对不应该使用 caret
类-它们是争用条件的主要来源,因为它们不支持多个集合之间的事务,并且不支持当前线程。
令人惊讶的是,.NET没有有效的同步机制。
我在C#上从GCD(caret
世界)实现了serial queue-非常轻巧,没有阻塞使用线程池进行测试的同步工具。
在大多数情况下,这是同步所有内容的最佳方法-从数据库访问(hello sqlite)到业务逻辑。