AutoResetEvent和ManualResetEvent

来源:http://www.cnblogs.com/liyulongBlog/archive/2017/11/27/7905262.html
-Advertisement-
Play Games

原文http://www.360doc.com/content/13/0829/14/4513754_310723961.shtml 一、作用 AutoResetEvent和ManualResetEvent可用於控制線程暫停或繼續,擁有重要的三個方法:WaitOne、Set和Reset。 這三個方法 ...


原文http://www.360doc.com/content/13/0829/14/4513754_310723961.shtml

一、作用

AutoResetEvent和ManualResetEvent可用於控制線程暫停或繼續,擁有重要的三個方法:WaitOneSetReset

這三個方法的官方定義並不好理解,什麼終止、非終止,亂七八糟的。在這裡,我們以一種通俗易懂的概念來說明。

 

二、比喻

如果把每個線程比作一輛汽車的話,AutoResetEventManualResetEvent就是公路上的收費站。

其中:

Reset 關閉收費站車閘禁止通行(攔截車輛才好收費啊);

WaitOne 收費員等待下一輛車輛過來(然後收費);

Set    開啟收費站車閘放行(交錢了就讓過去)。

 

三、AutoResetEvent和ManualResetEvent的區別

既然AutoResetEventManualResetEvent都是收費站,那麼它們之間有什麼不同之處嗎?

顧名思義,Auto即自動,Manual即手動,而Reset根據上面的比喻表示關閉車閘,也就是前者可自動關閉車閘,後者需手動關閉車閘。

自動關閉車閘:即一輛車交錢通過後,車閘會自動關閉,然後再等待下一輛車過來交費。即每輛車都要經過這麼幾個步驟:被阻 > 交費 > 通行 > 車閘關閉

手動關閉車閘:車閘打開後,車閘不會自動關閉,如果不手動關閉車閘(即調用ManualResetEvent.Reset()方法)的話,車輛會一輛接一輛地通過……

 

所以WaitOne收費操作取決於車閘是否關閉(Reset),如果車閘是開啟的,WaitOne的收費願望只能落空,收費站形同虛設。

 

四、AutoResetEvent和ManualResetEvent的初始狀態

通過設置AutoResetEventManualResetEvent構造函數可初始化收費站車閘狀態:

new Auto/ManualResetEvent(false)車閘預設關閉;
new Auto/ManualResetEvent(true) 車閘預設開啟。

如果new Auto/ManualResetEvent(true),即車閘預設開啟的話,WaitOne沒任何意義,車輛該通過還通過。

看下麵代碼:

  static EventWaitHandle _tollStation = new AutoResetEvent(true);//車閘預設開啟

        static void Main(string[] args)
        {
            new Thread(Car1).Start();
            Console.ReadKey();
        }

        static void Car1()
        {
            _tollStation.WaitOne();//因車閘預設開啟,WaitOne毫無意義,不會阻止車輛前行
            Console.WriteLine("噫!車閘是開的,我過來了!");
        }

運行將列印:

噫!車閘是開的,我過來了!

如果將new AutoResetEvent(true) 改為new AutoResetEvent(flase),即車閘預設為關閉狀態的話,將不會列印任何值,即車輛無法通過。

那如何才能通過呢?必須在主線程中調用Set方法,即打開車閘即可通過。

代碼:

static EventWaitHandle _tollStation = new AutoResetEvent(false);//車閘預設關閉

        static void Main(string[] args)
        {
            new Thread(Car1).Start();
            _tollStation.Set();//開啟車閘
            Console.ReadKey();
        }

        static void Car1()
        {
            _tollStation.WaitOne();//等待開啟車閘,即_event.Set();
            Console.WriteLine("車閘開啟,我過來了!");
        }

運行將列印:

車閘開啟,我過來了!

代碼很明瞭,就不解釋了,總之就是車閘預設關閉狀態下,只有打開車閘(調用Set方法 ),車輛才能通行。

 

五、用代碼闡釋AutoResetEvent的特性

代碼:

        static EventWaitHandle _tollStation = new AutoResetEvent(false);//車閘預設關閉

        static void Main(string[] args)
        {
            new Thread(Car1).Start();//車輛1
            new Thread(Car2).Start();//車輛2
            _tollStation.Set();
            Console.ReadKey();
        }

        static void Car1()
        {
            _tollStation.WaitOne();//等待開啟車閘,即_tollStation.Set();
            Console.WriteLine("車輛1,順利通過。");
        }

        static void Car2()
        {
            _tollStation.WaitOne();
            Console.WriteLine("車輛2,順利通過。!");
        }

運行將列印:

車輛1,順利通過。

雖然車輛1和車輛2都在運行,但只有車輛1順利通過。

因為_tollStation.Set()僅運行了一次,即車輛1通過後車閘被立即關閉,導致車輛2未被通過。

除非,在車輛1通過後再調用一次_tollStation.Set(),即再次打開車閘,車輛2才能通過:

        static AutoResetEvent _tollStation = new AutoResetEvent(false);//車閘預設關閉

        static void Main(string[] args)
        {
            new Thread(Car1).Start();//車輛1
            new Thread(Car2).Start();//車輛2
            _tollStation.Set();//開啟車閘,讓車輛1通過
            Console.ReadKey();
        }

        static void Car1()
        {
            _tollStation.WaitOne();//等待開啟車閘,即_tollStation.Set();
            Console.WriteLine("車輛1,順利通過。");
            _tollStation.Set();//再開啟一次車閘,讓車輛2通過
        }

        static void Car2()
        {
            _tollStation.WaitOne();
            Console.WriteLine("車輛2,順利通過。");
        }

運行將列印:

車輛1,順利通過。

車輛2,順利通過。

也就是每調用一次Set,僅有一個線程會繼續。換言之,有多少個線程就要調用多少次Set,線程才會全部繼續。

這也表明,AutoResetEvent是典型的隊列操作形式。

 

六、用代碼闡釋ManualResetEvent的特性

在上一個代碼塊中,_tollStation.Set()調用了兩次,兩輛車才順利通過。

那麼,有沒有什麼辦法,只調用一次_tollStation.Set()就讓兩輛或更多輛汽車順利通過呢?

答案是,將AutoResetEvent改為ManualResetEvent

 static EventWaitHandle _tollStation = new ManualResetEvent(false);//改為ManualResetEvent,車閘預設關閉

        static void Main(string[] args)
        {
            new Thread(Car1).Start();//車輛1
            new Thread(Car2).Start();//車輛2
            _tollStation.Set();//開啟車閘,所有車輛都會通過
            Console.ReadKey();
        }

        static void Car1()
        {
            _tollStation.WaitOne();//等待開啟車閘,即_tollStation.Set();
            Console.WriteLine("車輛1,順利通過。");
            //_tollStation.Set();//這裡不再需要了
        }

        static void Car2()
        {
            _tollStation.WaitOne();
            Console.WriteLine("車輛2,順利通過。");
        }

運行將列印:

車輛1,順利通過。

車輛2,順利通過。

這很好的說明瞭,ManualResetEvent開啟車閘後不會自動關閉這一特性。所以調用一次_tollStation.Set(),全部車輛將順利通過。

如果在某一時刻手動關閉了車閘,則後面的車輛將無法通過。如以下代碼:

 static EventWaitHandle _tollStation = new ManualResetEvent(false);//改為ManualResetEvent,車閘預設關閉

        static void Main(string[] args)
        {
            new Thread(Car1).Start();//車輛1
            new Thread(Car2).Start();//車輛2

            _tollStation.Set();//開啟車閘,放行
            Timer timer = new Timer(CloseDoor, null, 0, 2000);//2秒後關閉車閘

            Console.ReadKey();
        }

        static void Car1()
        {
            _tollStation.WaitOne();//等待開啟車閘,即_tollStation.Set();
            Console.WriteLine("車輛1,順利通過。");
        }

        static void Car2()
        {
            Thread.Sleep(3000);//睡眠3秒
            _tollStation.WaitOne();//當醒來後車閘已經被關閉
            Console.WriteLine("車輛2,順利通過。");//所以車輛2不會被通過
        }

        /// <summary>
        /// 2秒後關閉車閘
        /// </summary>
        static void CloseDoor(object o)
        {
            _tollStation.Reset();//關閉車閘
        }

運行將列印:

車輛1,順利通過。

而車輛2將不會通過,因為當車輛2醒來時,車閘在2秒前已被關閉。

 

七、總結

1、看起來,ManualResetEvent更加自由、開放。如果把AutoResetEvent看作是只能單人通過的獨木橋的話,那麼ManualResetEvent就像一座城門,一下子可以涌入千軍萬馬,當然你也可以隨時關閉城門,讓後面的人進不來。

2、AutoResetEvent.Set() = ManualResetEvent.Set() + ManualResetEvent.Reset();

3、如果共用資源僅允許一個線程單獨使用的情況下,可以選擇AutoResetEvent;如果共用資源允許多個線程同時使用,則可以選擇ManualResetEvent

4、如果要控制多個線程暫停、繼續,可以選擇ManualResetEvent


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linux的特點 1.免費的、開源的 2.支持多線程。多用戶的 3.安全性好 4.對記憶體和文件管理優越 5.linux最小隻需要4m->嵌入式開發 缺點: 操作相對困難 命令: shutdown -h now 立即進行關機 shutdown -r now 現在重新啟動電腦 reboot 現在重新啟 ...
  • 版本: Windows_server_2012-r2_x64 工具: VMware vSphere Client 鏡像地址: http://www.xpgod.com/soft/10718.html(地址為參考,可根據需求自行下載~) 首先鏈接虛機 鏈接成功後將本地資源進行上傳~ 滑鼠右擊datab ...
  • 從線程執行任務的方式上可以分為線程同步和線程非同步。而為了方便理解,後面描述中用“同步線程”指代與線程同步相關的線程,同樣,用“非同步線程”表示與線程非同步相關的線程。 線程非同步就是解決類似前面提到的執行耗時任務時界面控制項不能使用的問題。如創建一個次線程去專門執行耗時的任務,而其他如界面控制項響應這樣的任務 ...
  • var num = 1; var str = '1'; var test = 1; test == num //true 相同類型 相同值 test num //true 相同類型 相同值 test !== num //false test與num類型相同,其值也相同, 非運算肯定是false nu ...
  • Delphi DataTypeC# datatypeansistringstringbooleanboolbytebytecharcharcompdoublecurrencydecimaldoubledoubleextendeddoubleint64longint32intint16shortint... ...
  • 返回總目錄 本小節目錄 Replace Nested Conditional with Guard Claues(以衛語句取代嵌套條件表達式) Replace Conditional with Polymorphism(以多態取代條件表達式) 5Replace Nested Conditional ...
  • 這是使用ODP.NET鏈接Orcl資料庫常見錯誤,需要配置系統環境變數。 解決方法如下: 找到以下路徑文件:C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config 註意:修改前最好先備份以免.... 將下麵這段配置文件加 ...
  • 1 using System; 2 using System.Collections.Generic; 3 using System.Web; 4 using System.Web.Services; 5 using System.Data; 6 using Topevery.EOffice.Log ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...