日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET 中使用 Mutex 进行跨越进程边界的同步 - walterlv

發(fā)布時間:2025/7/25 asp.net 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET 中使用 Mutex 进行跨越进程边界的同步 - walterlv 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
.NET 中使用 Mutex 進(jìn)行跨越進(jìn)程邊界的同步 - walterlv 原文:.NET 中使用 Mutex 進(jìn)行跨越進(jìn)程邊界的同步 - walterlv

.NET 中使用 Mutex 進(jìn)行跨越進(jìn)程邊界的同步

Mutex 是 Mutual Exclusion 的縮寫,是互斥鎖,用于防止兩個線程同時對計算機上的同一個資源進(jìn)行訪問。不過相比于其他互斥的方式,Mutex 能夠跨越線程邊界。


本文內(nèi)容
  • Mutex 是什么?
  • 簡單的 Mutex(不能跨進(jìn)程互斥)
  • 創(chuàng)建跨進(jìn)程互斥的 Mutex
  • 處理異常情況
    • ApplicationException
    • AbandonedMutexException
    • 參考資料

Mutex 是什么?

與其他線程同步的方式一樣,Mutex 也提供對資源的互斥訪問;不過 Mutex 使用的系統(tǒng)資源會比 Monitor 更多,而 Monitor 就是實現(xiàn) C# 中 lock 關(guān)鍵字所用的鎖。

用更多的系統(tǒng)資源,帶來更強大的功能 —— Mutex 能進(jìn)行跨越應(yīng)用程序域邊界的封送,能進(jìn)行跨越進(jìn)程邊界的線程同步。

簡單的 Mutex(不能跨進(jìn)程互斥)

最簡單的 Mutex 的使用方法就是直接 new 出來,然后使用 Wait 進(jìn)行等待,使用 ReleaseMutex 進(jìn)行釋放。

private readonly Mutex _mutex = new Mutex();private void UseResource() {_mutex.WaitOne();// 等待一小段時間,假裝正在使用公共資源。這里的一段代碼在單個進(jìn)程之內(nèi)將無法重入。Thread.Sleep(500);_mutex.ReleaseMutex(); }

參數(shù)中有一個 initiallyOwned 參數(shù),如果指定為 true 表示創(chuàng)建這個 Mutex 的線程擁有這個資源(不需要等待),當(dāng)這個線程調(diào)用 ReleaseMutex 之后其他線程的 WaitOne 才會生效。

不過這種方式不能達(dá)到跨進(jìn)程同步的效果,所以實際上本文并不會過多描述這種互斥方式。

創(chuàng)建跨進(jìn)程互斥的 Mutex

要創(chuàng)建跨進(jìn)程互斥的 Mutex,必須要給 Mutex 指定名稱。

使用 new Mutex(false, "Walterlv.Mutex") 創(chuàng)建一個命名的互斥鎖,以便進(jìn)行跨進(jìn)程的資源互斥訪問。

在使用這個構(gòu)造函數(shù)重載的時候,第一個參數(shù) initiallyOwned 建議的取值為 false。因為當(dāng)你指定為 true 時,說明你希望此線程是初始創(chuàng)建此 Mutex 的線程,然而由于你是直接 new 出來的,所以你實質(zhì)上是無法得知你到底是不是第一個 new 出來的。

class Program {static async Task Main(string[] args){var program = new Program();while (true){// 不斷地嘗試訪問一段資源。這樣,當(dāng)多個進(jìn)程運行的時候,可以很大概率模擬出現(xiàn)資源訪問沖突。program.UseResource();await Task.Delay(50);}}private void UseResource(){var mutex = new Mutex(false, "Walterlv.Mutex");mutex.WaitOne();// 正在使用公共資源。// 這里的一段代碼將無法重入,即使是兩個不同的進(jìn)程。var path = @"C:\Users\lvyi\Desktop\walterlv.log";Console.WriteLine($"[{DateTime.Now:O}] 開始寫入文件……");File.AppendAllText(path, $"[{DateTime.Now:O}] 開始寫入文件……", Encoding.UTF8);Thread.Sleep(1000);File.AppendAllText(path, $"[{DateTime.Now:O}] 寫入文件完成。", Encoding.UTF8);Console.WriteLine($"[{DateTime.Now:O}] 寫入文件完成。");mutex.ReleaseMutex();} }

注意此程序在兩個進(jìn)程下的運行效果,明明我們等待使用資源的時間間隔只有 50 ms,但實際上等待時間是 1000 ms 左右。在關(guān)掉其中一個進(jìn)程之后,間隔恢復(fù)到了 50 ms 左右。

這說明 Mutex 的等待在這里起到了跨進(jìn)程互斥的作用。

當(dāng)你需要在是否是第一次創(chuàng)建出來的時候進(jìn)行一些特殊處理,就使用帶 createdNew 參數(shù)的構(gòu)造函數(shù)。

private void UseResource(){ -- var mutex = new Mutex(false, "Walterlv.Mutex"); ++ var mutex = new Mutex(true, "Walterlv.Mutex", out var createdNew); -- mutex.WaitOne(); ++ // 如果這個 Mutex 是由此處創(chuàng)建出來的,即 createdNew 為 true,說明第一個參數(shù) initiallyOwned 是真的發(fā)生了,于是我們就不需要等待。 ++ // 反之,當(dāng) createdNew 為 false 的時候,說明已經(jīng)有一個現(xiàn)成的 Mutex 已經(jīng)存在,我們在這里需要等待。 ++ if (!createdNew) ++ { ++ mutex.WaitOne(); ++ } ……mutex.ReleaseMutex();}

處理異常情況

ApplicationException

mutex.ReleaseMutex(); 方法只能被當(dāng)前擁有它的線程調(diào)用,如果某個線程試圖調(diào)用這個函數(shù),卻沒有擁有這個 Mutex,就會拋出 ApplicationException。

怎樣為擁有呢?還記得前面構(gòu)造函數(shù)中的 initiallyOwned 參數(shù)嗎?就是在指定自己是否是此 Mutex 的擁有者的(實際上我們還需要使用 createdNew 來輔助驗證這一點)。

當(dāng)一個線程沒有擁有這個 Mutex 的時候,需要使用 WaitOne 來等待獲得這個鎖。

AbandonedMutexException

class Program {static async Task Main(string[] args){// 開啟一個線程,在那個線程中丟掉獲得的 Mutex。var thread = new Thread(AbandonMutex);thread.Start();// 不要讓進(jìn)程退出,否則 Mutex 就會被系統(tǒng)回收。Console.Read();}private static void AbandonMutex(){// 獲得一個 Mutex,然后就不再釋放了。// 由于此線程會在 WaitOne 執(zhí)行結(jié)束后退出,所以這個 Mutex 就被丟掉了。var mutex = new Mutex(false, "Walterlv.Mutex");mutex.WaitOne();} }

上面的這段代碼,當(dāng)你第一次運行此進(jìn)程并且保持此進(jìn)程不退出的時候并沒有什么異樣。但是你再啟動第二個進(jìn)程實例的話,就會在 WaitOne 那里收到一個異常 —— AbandonedMutexException。

所以如果你不能在一處代碼中使用 try-finally 來確保在獲得鎖之后一定會釋放的話,那么強烈建議在 WaitOne 的時候捕獲異常。順便提醒,try-finally 中不能有異步代碼,你可以參見:在有 UI 線程參與的同步鎖(如 AutoResetEvent)內(nèi)部使用 await 可能導(dǎo)致死鎖。

也就是說,當(dāng)你需要等待的時候,catch 一下異常。在 catch 完之后,你并不需要再次使用 WaitOne 來等待,因為即便發(fā)生了異常,你也依然獲得了鎖。這一點你可以通過調(diào)用 ReleaseMutex 來驗證,因為前面我們說了只有擁有鎖的線程才可以釋放鎖。

private static void WaitOne() {var mutex = new Mutex(false, "Walterlv.Mutex");try{mutex.WaitOne();}catch (AbandonedMutexException ex){Console.WriteLine("發(fā)現(xiàn)被遺棄的鎖");}Console.WriteLine("獲得了鎖"); }

參考資料

  • Mutexes - Microsoft Docs
  • Mutex Constructor (System.Threading) - Microsoft Docs
  • Mutex Class (System.Threading) - Microsoft Docs

本文會經(jīng)常更新,請閱讀原文: https://walterlv.com/post/mutex-in-dotnet.html ,以避免陳舊錯誤知識的誤導(dǎo),同時有更好的閱讀體驗。

本作品采用 知識共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議 進(jìn)行許可。歡迎轉(zhuǎn)載、使用、重新發(fā)布,但務(wù)必保留文章署名 呂毅 (包含鏈接: https://walterlv.com ),不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布。如有任何疑問,請 與我聯(lián)系 (walter.lv@qq.com) 。

posted on 2019-01-03 13:29 NET未來之路 閱讀(...) 評論(...) 編輯 收藏

轉(zhuǎn)載于:https://www.cnblogs.com/lonelyxmas/p/10213684.html

《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的.NET 中使用 Mutex 进行跨越进程边界的同步 - walterlv的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。