.NET 多线程同步包含SpinLock,Monitor(lock语法糖),WaitHandle族(ManualResetEvent、AutoResetEvent、Semaphore,Mutex等)
1. WaitHandle族(ManualResetEvent,AutoResetEvent,Semaphore等)
ManualResetEvent,AutoResetEvent是只允许一个线程访问共享资源,
ManualResetEvent,AutoResetEvent区别在于Set()
,ManualResetEvent实例调用Set()后所有线程允许运行不再阻塞,AutoResetEvent实例调用Set()后只允许运行一次且运行后立即阻塞
Semaphore 允许一个或多个
2.SpinLock
SpinLock即自旋锁,尝试获取该锁的线程持续不断的check是否可以获得。此时线程仍然是激活状态,只是在空转,浪费cpu而已
但是spinlock避免了线程调度和上下文切换,如果锁的时间极短的话,使用该锁反而效率会高,
SpinLock允许你查询是否锁已经被其他线程占用,通过IsHeld属性。
3.Mutex
Mutex是可以进程间同步的同步基元
名称 | 说明 | |
---|---|---|
![]() |
Mutex() |
使用默认属性初始化 Mutex 类的新实例。 |
![]() |
Mutex(Boolean) |
使用 Boolean 值(指示调用线程是否应具有互斥体的初始所有权)初始化 Mutex 类的新实例。 |
![]() |
Mutex(Boolean, String) |
使用 Boolean 值(指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称)初始化 Mutex 类的新实例。 |
![]() |
Mutex(Boolean, String, Boolean) |
使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权的 Boolean 值初始化 Mutex 类的新实例。 |
![]() |
Mutex(Boolean, String, Boolean, MutexSecurity) |
使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权以及访问控制安全是否已应用到命名互斥体的 Boolean 变量初始化 Mutex 类的新实例。 |
Mutex并不适合于有相互消息通知的同步;另一方面而我们也多次提到局部Mutex应该被Monitor/lock所取代;而跨应用程序的、相互消息通知的同步由将在后面讲到的EventWaiteHandle/AutoResetEvent/ManualResetEvent承担更合适。所以,Mutex在.net中应用的场景似乎不多。不过,Mutex有个最常见的用途:用于控制一个应用程序只能有一个实例运行。
using System; using System.Threading; class MutexSample { private static Mutex mutex = null; //设为Static成员,是为了在整个程序生命周期内持有Mutex static void Main() { bool firstInstance; mutex = new Mutex(true, @"Global\MutexSampleApp", out firstInstance); try { if (!firstInstance) { Console.WriteLine ("已有实例运行,输入回车退出……"); Console.ReadLine(); return; } else { Console.WriteLine ("我们是第一个实例!"); for (int i=60; i > 0; --i) { Console.WriteLine (i); Thread.Sleep(1000); } } } finally { //只有第一个实例获得控制权,因此只有在这种情况下才需要ReleaseMutex,否则会引发异常。 if (firstInstance) { mutex.ReleaseMutex(); } mutex.Close(); mutex = null; } } }
这是一个控制台程序,你可以在编译后尝试一次运行多个程序,结果当然总是只有一个程序在倒数计时。你可能会在互联网上找到其它实现应用程序单例的方法,比如利用 Process 查找进程名、利用Win32 API findwindow 查找窗体的方式等等,不过这些方法都不能保证绝对的单例。因为多进程和多线程是一样的,由于CPU时间片随机分配的原因,可能出现多个进程同时检查到没有其它实例运行的状况。这点在CPU比较繁忙的情况下容易出现,现实的例子比如傲游浏览器。即便你设置了只允许一个实例运行,当系统比较忙的时候,只要你尝试多次打开浏览器,那就有可能“幸运”的打开若干独立的浏览器窗口。
别忘了,要实现应用程序的单例,需要在在整个应用程序运行过程中都保持Mutex,而不只是在程序初始阶段。所以,例子中Mutex的建立和销毁代码包裹了整个Main()函数。
使用Mutex需要注意的两个细节
原文:https://www.cnblogs.com/lldbang/p/13388635.html