Answers:
好问题。我可能错了..让我尝试..我的原始答案的修订版#..有了一点更多的了解。谢谢你让我读:)
锁(obj)
监控器
使用锁或监视器对于防止同时执行线程敏感的代码块很有用,但是这些构造不允许一个线程将事件传递给另一个线程。这需要同步事件,这些事件是具有信号状态和未信号状态两种状态之一的对象,可用于激活和挂起线程。互斥量,信号量是操作系统级别的概念。例如,使用命名的互斥锁,您可以在多个(托管)exe之间进行同步(确保仅在计算机上运行应用程序的一个实例。)
互斥体:
信号量(伤了我的大脑)。
Monitor
不允许交流是不正确的;您仍然可以Pulse
与Monitor
关于“使用其他.Net同步类”-您应该了解的其他一些:
CCR / TPL(并行扩展 CTP)中还有更多(低开销)锁定结构-但是IIRC,它们将在.NET 4.0中提供
正如ECMA中所述,您可以从Reflected方法中观察到,lock语句基本上等效于
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
…
}
finally {
System.Threading.Monitor.Exit(obj);
}
从上述示例中,我们可以看到Monitor可以锁定对象。
当您需要进程间同步时,互斥锁很有用,因为它们可以锁定字符串标识符。不同的进程可以使用相同的字符串标识符来获取锁。
信号量就像类固醇上的互斥量,它们通过提供最大数量的并发访问来允许并发访问。一旦达到限制,信号量就会开始阻止对资源的任何进一步访问,直到调用者之一释放该信号量为止。
我为DotGNU中的线程做了类和CLR支持,我有几点想法...
除非您需要跨进程锁,否则应始终避免使用Mutex&Semaphores。.NET中的这些类是Win32 Mutex和Semaphores的包装,它们的重量非常大(它们需要将上下文切换到内核中,这很昂贵-尤其是在您的锁不在争用状态时)。
正如其他提到的那样,C#lock语句是Monitor.Enter和Monitor.Exit(存在于try / finally中)的编译器魔术。
监视器具有一个简单但功能强大的信号/等待机制,而互斥量通过Monitor.Pulse / Monitor.Wait方法没有。Win32等效项是通过CreateEvent生成的事件对象,该对象实际上在.NET中也以WaitHandles的形式存在。Pulse / Wait模型类似于Unix的pthread_signal和pthread_wait,但速度更快,因为它们在完全无争议的情况下可以完全是用户模式的操作。
Monitor.Pulse / Wait使用简单。在一个线程中,我们锁定一个对象,检查一个标志/状态/属性,如果不是我们期望的,请调用Monitor.Wait,它将释放锁定并等待直到发送脉冲。等待返回时,我们循环返回并再次检查标志/状态/属性。在另一个线程中,只要更改标志/状态/属性,然后调用PulseAll来唤醒所有侦听线程,就锁定对象。
通常,我们希望类是线程安全的,因此我们在代码中加了锁。但是,通常情况下,我们的类只会被一个线程使用。这意味着锁不必要地减慢了我们的代码的速度...这是CLR中巧妙的优化可以帮助提高性能的地方。
我不确定Microsoft的锁的实现,但是在DotGNU和Mono中,锁状态标志存储在每个对象的标头中。.NET(和Java)中的每个对象都可以变成一个锁,因此每个对象都需要在其标头中支持此锁。在DotGNU实现中,有一个标志允许您为用作锁定的每个对象使用全局哈希表-这样做的好处是消除了每个对象的4字节开销。这对于内存(特别是对于线程不多的嵌入式系统)而言不是很好,但会影响性能。
Mono和DotGNU都有效地使用互斥锁来执行锁定/等待,但是除非有必要,否则使用自旋锁样式的比较和交换操作来消除实际执行硬锁的需要:
您可以在此处查看如何实现监视器的示例:
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
如果可以的话,我会尽量避免使用“ lock()”,“ Mutex”和“ Monitor”。
在.NET 4中签出新的命名空间System.Collections.Concurrent。
它具有一些不错的线程安全的集合类。
http://msdn.microsoft.com/zh-CN/library/system.collections.concurrent.aspx
并发词典岩石!我不再需要手动锁定!
在大多数情况下,您不应使用锁(= Monitors)或互斥/信号量。它们都阻塞了当前线程。
而且你绝对不应该使用 System.Collections.Concurrent
类-它们是争用条件的主要来源,因为它们不支持多个集合之间的事务,并且不支持当前线程。
令人惊讶的是,.NET没有有效的同步机制。
我在C#上从GCD(世界)实现了串行队列Objc/Swift
-非常轻巧,没有阻塞使用线程池的同步工具以及测试。
在大多数情况下,这是同步所有内容的最佳方法-从数据库访问(hello sqlite)到业务逻辑。