临界区:描述一段在同一时候只能被一个线程访问的代码。
1.Lock关键字实现临界区,通过"对象锁"的方式,只能锁定引用类型不能锁定值类型,其内部使用Monitor类实现的。例如:
lock(_locker) { DoSomething(); } // 等效于 System.Object obj = (System.Object)_locker; System.Threading.Monitor.Enter(obj); try { DoSomething(); } finally { System.Threading.Monitor.Exit(obj); }
2.Monitor监视器是一个静态类,不能实例化,其实现临界区的方式是Enter和Exit,并且其还有线程通信的功能,通过Wait()可以释放对象上的锁并且阻塞当前线程使线程进入“WaitSleepJoin”状态,通过Pulse()可以唤醒阻塞线程使线程进入"Running”状态,参与对对象锁的争夺。
3.Mutex互斥量与Monitor相似,只有拥有互斥对象的的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被其他多个线程所访问。当前占据资源的线程在任务处理完后应将拥有互斥对象交出,以便其他线程在获得后得以访问资源。互斥量不仅用于同一程序的不同线程中实现资源的安全共享,还能够在不同应用程序的线程直接实现资源的安全共享。(全局互斥量)
4.AutoResetEvent的Set方法与Monitor的Pulse类似,但是Set的作用不仅仅是唤醒线程,而是释放线程,其能够让线程继续工作,Pulse只是唤醒线程进入Running状态,不保证线程能够获得对象锁,另外Pulse调用的状态不会被维护,即如果调用的时候并没有线程在等待,那么下一次调用Monitor.Wait的时候线程仍会阻塞,而AutoResetEvent.Set不一样,如果调用的时候没有线程阻塞,那么EventWaitHandle将会保持终止状态直到下一个WaitOne调用,该线程会继续运行不会阻塞,下一个调用WaitOne的线程会阻塞。
5.线程相关性,如Mutex和Monitor,只有获得对象锁的线程才能够调用Wait/Pulse/Exit/ReleaseMutex等接口,否则会引发异常。相反,EventWaitHandle以及它的派生类AutoResetEvent和ManualResetEvent都是线程无关的,任何线程都能够发送信号以阻塞运行线程。
6.EventWaitHandle可以指定同步事件名称用于跨进程同步通信。而其派生类AutoResetEvent和ManualResetEvent永远是局部Local的,无法用于进程间的通信。
7.Mutex可以实现资源互斥访问但几乎不具有通信能力,而EventWaitHandle有强大的通信能力但却不能实现资源互斥访问。
8.信号量Semaphore与Mutex一样属于"锁",只不过Mutex永远只允许一个线程拥有它,而Semaphore可以允许多个线程进入并发访问资源,如果设置最大访问线程数为一,则其效果与Mutex差不多。
9.读写锁ReaderWriterLock用于同步对资源的访问,在任何给定时间,它允许多个线程的并发读访问权限,或者单个线程的写访问权限。在某个资源不常更改的情况下ReaderWriterLock提供比简单的一次锁定(Monitor)更好的吞吐量。