ManualResetEvent 與 AutoResetEvent 區別


 在多線程開發中,時常用到 ManualResetEvent 與 AutoResetEvent  。 它們如同道路交通中的信號燈。兩者之間有什么區別呢?

共同點:

  均繼承 EventWaitHandle 接口,因此,均具有以下功能:

Reset() //紅燈

Set() //綠燈

WaitOne() // 等待信號

 

不同點:

AutoResetEvent   收到 Set 后 , 一次只能執行一個線程,其它線程繼續 WaitOne 。

ManualResetEvent  收到 Set 后,所有處理 WaitOne 狀態線程均繼續執行。

 

msdn 提到(如果沒有線程 處於WaitOne() 狀態,而調用 Set , AutoResetEvent 將保持Set 狀態):

調用Set信號AutoResetEvent釋放等待線程。 AutoResetEvent 將保持終止狀態直到一個等待線程釋放,並自動返回到非信號狀態。 如果沒有線程處於等待狀態,狀態將無限期地保持已發出信號。

因此通常WatiOne 之前,先 Reset() 一下,清除Set 信號

 

需要注意的是(兩個 Set 調用之間時間較短,第二個 Set 信號可能會丟失,因此連續 Set 調用,中間需要 Sleep 一定時間):

不能保證的每個調用Set方法將釋放一個線程。 如果兩次調用太靠近在一起,以便第二次調用前釋放線程發生,只有一個線程被釋放。 就像第二次調用未發生。 此外,如果Set時沒有等待的線程調用和AutoResetEvent已終止,則調用不起作用。

 

有網友說:

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

 

個人理解 ,這只是原理層面含義,實際使用過程中,有差別的,如下示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace testManualResetEvent
{
    class Program
    {
        static object objManualResetEvent = new object();
        static System.Threading.ManualResetEvent manu = new System.Threading.ManualResetEvent(false);
         //static System.Threading.AutoResetEvent manu = new System.Threading.AutoResetEvent(false);
        static void Main(string[] args)
        {
           
            for (int i = 0; i < 10; i++)
            {
                System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(() => { Product(); }));
                t.Start();
            }
            
            manu.Set();
            manu.Reset();

            Console.ReadKey();
        }

        static void Product()
        {
            manu.WaitOne(10000);
            Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
        }
    }
}

 

實際執行結果 , 在 執行 set 后 reset 前 ,有多少個線程喚起執行,無法預料: 

 

需要加鎖 ,確保一次通過一個線程:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace testManualResetEvent
{
    class Program
    {
        static object objManualResetEvent = new object();
        static System.Threading.ManualResetEvent manu = new System.Threading.ManualResetEvent(false);
         //static System.Threading.AutoResetEvent manu = new System.Threading.AutoResetEvent(false);
        static void Main(string[] args)
        {
           
            for (int i = 0; i < 10; i++)
            {
                System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(() => { Product(); }));
                t.Start();
            }
            
            manu.Set();

            //System.Threading.Thread.Sleep(100); //連續 set 需要 sleep
            //manu.Set();
            //manu.Reset();

            //System.Threading.Thread.Sleep(100);
            //manu.Set();
            //manu.Reset();

            Console.ReadKey();
        }

        static void Product()
        {
            lock (objManualResetEvent)
            {
                manu.WaitOne(10000);
          manu.Reset(); Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); } } } }

 

執行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM