Semaphore(信號量)


  場景:當多個任務或線程並行運行時,難以避免的對某些有限的資源進行並發的訪問

 

  可以考慮使用信號量來進行這方面的控制(System.Threading.Semaphore)是表示一個Windows內核的信號量對象(操作系統級別,可以跨進程或AppDomain)。如果預計等待的時間較短,使用SemaphoreSlim(單進程)帶來的開銷更小。關於兩者的區別如下:

  System.Threading.Semaphore 類表示一個命名(系統范圍內)或本地信號量。它是環繞 Win32 信號量對象的精簡包裝器。Win32 信號量是計數信號量,該可用於控制對資源池的訪問。

  SemaphoreSlim 類表示一個輕量、快速的信號量,可在等待時間預計很短的情況下用於在單個進程內等待。 SemaphoreSlim 盡可能多地依賴公共語言運行時 (CLR) 提供的同步基元。但是,它還提供延遲初始化、基於內核的等待句柄,作為在多個信號量上進行等待的必要支持。 SemaphoreSlim 也支持使用取消標記,但不支持命名信號量或使用用於同步的等待句柄。Semaphore的WaitOne或者Release方法的調用大約會耗費1微秒的系統時間,而優化后的SemaphoreSlim則需要大致四分之一微秒。在計算中大量頻繁使用它的時候SemaphoreSlim還是優勢明顯,加上SemaphoreSlim還豐富了不少接口,更加方便我們進行控制,所以在4.0以后的多線程開發中,推薦使用SemaphoreSlim(相關鏈接:https://msdn.microsoft.com/zh-cn/library/z6zx288a(v=vs.110).aspx)

  這里我們只討論System.Threading.Semaphore,.Net FrameWork中的信號量通過跟蹤進入和離開的任務或線程來協調對資源的訪問。號量需要知道資源的最大數量,當一個任務進入時,資源計數器會被減1(獲取到訪問許可證),當計數器為0時,如果有任務訪問資源(未被授權訪問許可證),它會被阻塞,直到有任務離開為止

  介紹一下Semaphore這個類的常用的初始化構造方法,如下,請仔細閱讀注釋部分。

   /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Threading.Semaphore"/> class, specifying the maximum number of concurrent entries and optionally reserving some entries.
    /// </summary>
    /// <param name="initialCount">The initial number of requests for the semaphore that can be granted concurrently.</param><param name="maximumCount">The maximum number of requests for the semaphore that can be granted concurrently.</param><exception cref="T:System.ArgumentException"><paramref name="initialCount"/> is greater than <paramref name="maximumCount"/>.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maximumCount"/> is less than 1.-or-<paramref name="initialCount"/> is less than 0.</exception>
    [SecuritySafeCritical]
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public Semaphore(int initialCount, int maximumCount);

  initialCount:信號量可以接受的並發請求數量的初始容量

  maximumCount:信號量可以接受的並發請求數量的最大容量

  那么看下面這個demo。

 1 class Program
 2     {
 3         //創建一個可授權2個許可證的信號量,且初始值為2
 4         static Semaphore _semaphore = new Semaphore(2, 2);
 5 
 6         static void Main(string[] args)
 7         {
 8             Task.Factory.StartNew(() => DoWork());
 9             Task.Factory.StartNew(() => DoWork());
10             Task.Factory.StartNew(() => DoWork());
11 
12             Console.ReadLine();
13         }
14 
15         static void DoWork()
16         {
17             try
18             {
19                 Console.WriteLine(string.Format("Thread {0} 正在等待一個許可證……", Thread.CurrentThread.ManagedThreadId));
20                 _semaphore.WaitOne();
21                 Console.WriteLine(string.Format("Thread {0} 申請到許可證……", Thread.CurrentThread.ManagedThreadId));
22                 Thread.Sleep(5000);
23                 Console.WriteLine(string.Format("Thread {0} 釋放許可證……", Thread.CurrentThread.ManagedThreadId));
24             }
25             finally
26             {
27                 _semaphore.Release();
28             }
29         }
30     }
View Code

  多個線程申請獲取許可證,其中線程A通過_semaphore.WaitOne拿到了一個許可證,進行initialCount-1操作,業務完成之后再調用_semaphore.Release釋放了這個許可證,initialCount+1。如果設置最大並發數=1,那么當前僅有1個線程能夠拿到這個許可,其他線程都處於阻塞狀態,直到該線程釋放為止。當然信號量不可能永久的阻塞在那里。信號量也提供了超時處理機制。方法是在Wait函數中傳入一個超時等待時間 - Wait(int TIMEOUT)。當Wait返回值為false時表明它超時了。如果傳入了 -1,則表示無限期的等待。

  關於信號量和鎖/隊列的概念

  信號量(Semaphore)是一種CLR中的內核同步對象。與標准的排他鎖對象(Monitor,Mutex,SpinLock)不同的是,它不是一個排他的鎖對象,它與SemaphoreSlim,ReaderWriteLock等一樣允許多個有限的線程同時訪問共享內存資源。Semaphore就好像一個柵欄,有一定的容量,當里面的線程數量到達設置的最大值時候,就沒有線程可以進去。然后,如果一個線程工作完成以后出來了,那下一個線程就可以進去了。Semaphore的WaitOne或Release等操作分別將自動地遞減或者遞增信號量的當前計數值。當線程試圖對計數值已經為0的信號量執行WaitOne操作時,線程將阻塞直到計數值大於0。
  互斥量(Mutex) ,互斥量表現互斥現象的數據結構,也被當作二元信號燈。一個互斥基本上是一個多任務敏感的二元信號,它能用作同步多任務的行為,它常用作保護從中斷來的臨界段代碼並且在共享同步使用的資源。
Mutex本質上說就是一把鎖,提供對資源的獨占訪問,所以Mutex主要的作用是用於互斥。Mutex對象的值,只有0和1兩個值。這兩個值也分別代表了Mutex的兩種狀態。值為0, 表示鎖定狀態,當前對象被鎖定,用戶進程/線程如果試圖Lock臨界資源,則進入排隊等待;值為1,表示空閑狀態,當前對象為空閑,用戶進程/線程可以Lock臨界資源,之后Mutex值減1變為0。
  Enqueue和Lock實際上是一個事物的兩個名字。他們都支持隊列(queue)和並發(concurrency)。他們在隊列中的管理方式是“先進先出”(FIFO)的方式。

 


免責聲明!

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



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