<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Mutex 中文為互斥,Mutex 類叫做互斥鎖。它還可用於程序間同步的同步基元。
Mutex 跟 lock 相似,但是 Mutex 支援多個程序。Mutex 大約比 lock 慢 20 倍。
互斥鎖(Mutex),用於多執行緒中防止兩條執行緒同時對一個公共資源進行讀寫的機制。
Windows 作業系統中,Mutex 同步物件有兩個狀態:
Mutex 只能在獲得鎖的執行緒中,釋放鎖。
Mutex 類其建構函式如下:
建構函式 | 說明 |
---|---|
Mutex() | 使用預設屬性初始化 Mutex類的新範例。 |
Mutex(Boolean) | 使用 Boolean 值(指示呼叫執行緒是否應具有互斥體的初始所有權)初始化 Mutex 類的新範例。 |
Mutex(Boolean, String) | 使用 Boolean 值(指示呼叫執行緒是否應具有互斥體的初始所有權以及字串是否為互斥體的名稱)初始化 Mutex 類的新範例。 |
Mutex(Boolean, String, Boolean) | 使用可指示呼叫執行緒是否應具有互斥體的初始所有權以及字串是否為互斥體的名稱的 Boolean 值和當執行緒返回時可指示呼叫執行緒是否已賦予互斥體的初始所有權的 Boolean 值初始化 Mutex 類的新範例。 |
Mutex 對於程序同步有所幫助,例如其應用場景主要是控制系統只能執行一個此程式的範例。
Mutex 建構函式中的 String型別引數 叫做互斥量而互斥量是全域性的作業系統物件。
Mutex 只要考慮實現程序間的同步,它會耗費比較多的資源,程序內請考慮 Monitor/lock。
Mutex 的常用方法如下:
方法 | 說明 |
---|---|
Close() | 釋放由當前 WaitHandle 佔用的所有資源。 |
Dispose() | 釋放由 WaitHandle 類的當前範例佔用的所有資源。 |
OpenExisting(String) | 開啟指定的已命名的互斥體(如果已經存在)。 |
ReleaseMutex() | 釋放 Mutex一次。 |
TryOpenExisting(String, Mutex) | 開啟指定的已命名的互斥體(如果已經存在),並返回指示操作是否成功的值。 |
WaitOne() | 阻止當前執行緒,直到當前 WaitHandle 收到訊號。 |
WaitOne(Int32) | 阻止當前執行緒,直到當前 WaitHandle 收到訊號,同時使用 32 位帶符號整數指定時間間隔(以毫秒為單位)。 |
WaitOne(Int32, Boolean) | 阻止當前執行緒,直到當前的 WaitHandle 收到訊號為止,同時使用 32 位帶符號整數指定時間間隔,並指定是否在等待之前退出同步域。 |
WaitOne(TimeSpan) | 阻止當前執行緒,直到當前範例收到訊號,同時使用 TimeSpan 指定時間間隔。 |
WaitOne(TimeSpan, Boolean) | 阻止當前執行緒,直到當前範例收到訊號為止,同時使用 TimeSpan 指定時間間隔,並指定是否在等待之前退出同步域。 |
關於 Mutex 類,我們可以先通過幾個範例去了解它。
下面是一個範例,用於控制系統只能執行一個此程式的範例,不允許同時啟動多次。
class Program { // 第一個程式 const string name = "www.whuanle.cn"; private static Mutex m; static void Main(string[] args) { // 本程式是否是 Mutex 的擁有者 bool firstInstance; m = new Mutex(false,name,out firstInstance); if (!firstInstance) { Console.WriteLine("程式已在執行!按下確認鍵退出!"); Console.ReadKey(); return; } Console.WriteLine("程式已經啟動"); Console.WriteLine("按下確認鍵退出執行"); Console.ReadKey(); m.ReleaseMutex(); m.Close(); return; } }
上面的程式碼中,有些地方前面沒有講,沒關係,我們執行一下生成的程式先。
Mutex 的工作原理:
當兩個或兩個以上的執行緒同時存取共用資源時,作業系統需要一個同步機制來確保每次只有一個執行緒使用資源。
Mutex 是一種同步基元,Mutex 僅向一個執行緒授予獨佔存取共用資源的許可權。這個許可權依據就是 互斥體,當一個執行緒獲取到互斥體後,其它執行緒也在試圖獲取互斥體時,就會被掛起(阻塞),直到第一個執行緒釋放互斥體。
對應我們上一個程式碼範例中,範例化 Mutex 類別建構函式如下:
m = new Mutex(false,name,out firstInstance);
其建構函式原型如下:
public Mutex (bool initiallyOwned, string name, out bool createdNew);
前面我們提出過,Mutex 物件有兩種狀態,signaled 和 nonsignaled。
通過 new 來範例化 Mutex 類,會檢查系統中此互斥量 name 是否已經被使用,如果沒有被使用,則會建立 name 互斥量並且此執行緒擁有此互斥量的使用權;此時 createdNew == true
。
那麼 initiallyOwned ,它的作用是是否允許執行緒是否能夠獲取到此互斥量的初始化所有權。因為我們希望只有一個程式能夠在後臺執行,因此我們要設定為 false。
驅動開發中關於Mutex :https://docs.microsoft.com/zh-cn/windows-hardware/drivers/kernel/introduction-to-mutex-objects
對了, Mutex 的 引數中,name 是非常有講究的。
在執行終端服務的伺服器上,命名系統 mutex 可以有兩個級別的可見性。
如果在建立已命名的 mutex 時未指定字首,則採用字首 "Local"。 在終端伺服器對談中,兩個互斥體的名稱只是它們的字首不同,它們都是對終端伺服器對談中的所有程序都可見。
也就是說,字首名稱 "Global" 和 "Local" 描述互斥體名稱相對於終端伺服器對談的作用域,而不是相對於程序。
請參考:
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.mutex?view=netcore-3.1
https://www.jb51.net/article/237313.htm
這裡要實現,當同時點選一個程式時,只能有一個範例A可以執行,其它範例進入等待佇列,等待A執行完畢後,然後繼續執行佇列中的下一個範例。
我們將每個程式比作一個人,模擬一個廁所坑位,每次只能有一個人上廁所,其他人需要排隊等候。
使用 WaitOne()
方法來等待別的程序釋放互斥量,即模擬排隊;ReleaseMutex()
方法解除對坑位的佔用。
class Program { // 第一個程式 const string name = "www.whuanle.cn"; private static Mutex m; static void Main(string[] args) { // wc 還有沒有位置 bool firstInstance; m = new Mutex(true,name,out firstInstance); // 已經有人在上wc if (!firstInstance) { // 等待執行的範例退出,此程序才能執行。 Console.WriteLine("排隊等待"); m.WaitOne(); GoWC(); return; } GoWC(); return; } private static void GoWC() { Console.WriteLine(" 開始上wc"); Thread.Sleep(1000); Console.WriteLine(" 開門"); Thread.Sleep(1000); Console.WriteLine(" 關門"); Thread.Sleep(1000); Console.WriteLine(" xxx"); Thread.Sleep(1000); Console.WriteLine(" 開門"); Thread.Sleep(1000); Console.WriteLine(" 離開wc"); m.ReleaseMutex(); Thread.Sleep(1000); Console.WriteLine(" 洗手"); } }
此時,我們使用了
m = new Mutex(true,name,out firstInstance);
一個程式結束後,要允許其它執行緒能夠建立 Mutex 物件獲取互斥量,需要將建構函式的第一個引數設定為 true。
你也可以改成 false,看看會報什麼異常。
你可以使用 WaitOne(Int32)
來設定等待時間,單位是毫秒,超過這個時間就不排隊了,去別的地方上廁所。
為了避免出現問題,請考慮在 finally 塊中執行 m.ReleaseMutex()
。
這裡我們實現一個這樣的場景:
父程序 Parent 啟動子程序 Children ,等待子程序 Children 執行完畢,子程序退出,父程序退出。
新建一個 .NET Core 控制檯專案,名稱為 Children,其 Progarm 中的程式碼如下
using System; using System.Threading; namespace Children { class Program { const string name = "程序同步範例"; private static Mutex m; static void Main(string[] args) { Console.WriteLine("子程序被啟動..."); bool firstInstance; // 子程序建立互斥體 m = new Mutex(true, name, out firstInstance); // 按照我們設計的程式,建立一定是成功的 if (firstInstance) { Console.WriteLine("子執行緒執行任務"); DoWork(); Console.WriteLine("子執行緒任務完成"); // 釋放互斥體 m.ReleaseMutex(); // 結束程式 return; } else { Console.WriteLine("莫名其妙的異常,直接退出"); } } private static void DoWork() { for (int i = 0; i < 5; i++) { Console.WriteLine("子執行緒工作中"); Thread.Sleep(TimeSpan.FromSeconds(1)); } } } }
然後釋出或生成專案,開啟程式檔案位置,複製執行緒檔案路徑。
建立一個新專案,名為 Parent 的 .NET Core 控制檯,其 Program 中的程式碼如下:
using System; using System.Diagnostics; using System.Threading; namespace Parent { class Program { const string name = "程序同步範例"; private static Mutex m; static void Main(string[] args) { // 晚一些再執行,我錄屏要對正視窗位置 Thread.Sleep(TimeSpan.FromSeconds(3)); Console.WriteLine("父程序啟動!"); new Thread(() => { // 啟動子程序 Process process = new Process(); process.StartInfo.UseShellExecute = true; process.StartInfo.CreateNoWindow = false; process.StartInfo.WorkingDirectory = @"../../../ConsoleApp9ChildrenbinDebugnetcoreapp3.1"; process.StartInfo.FileName = @"../../../ConsoleApp9ChildrenbinDebugnetcoreapp3.1Children.exe"; process.Start(); process.WaitForExit(); }).Start(); // 子程序啟動需要一點時間 Thread.Sleep(TimeSpan.FromSeconds(1)); // 獲取互斥體 bool firstInstance; m = new Mutex(true, name, out firstInstance); // 說明子程序還在執行 if (!firstInstance) { // 等待子程序執行結束 Console.WriteLine("等待子程序執行結束"); m.WaitOne(); Console.WriteLine("子程序執行結束,程式將在3秒後自動退出"); m.ReleaseMutex(); Thread.Sleep(TimeSpan.FromSeconds(3)); return; } } } }
請將 Children 專案的程式檔案路徑,替換到 Parent 專案啟動子程序的那部分字串中。
然後啟動 Parent.exe,可以觀察到如下圖的執行過程:
建構函式中,如果為 name
指定 null
或空字串,則將建立一個本地 Mutex 物件,只會在程序內有效。
Mutex 有些使用方法比較隱晦,可以參考 https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.mutex.-ctor?view=netcore-3.1
另外開啟互斥體,請參考
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.mutex.openexisting?view=netcore-3.1
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.mutex.tryopenexisting?view=netcore-3.1
到此這篇關於C#多執行緒系列之程序同步Mutex類的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45