1. 程式人生 > >c# Semaphore(訊號量)

c# Semaphore(訊號量)

http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813635.html

http://hi.baidu.com/bloodcrystal/blog/item/00ebd7f9da5aadd2b58f317c.html

訊號量 Semaphore

類似互斥鎖,但它可以允許多個執行緒同時訪問一個共享資源

通過使用一個計數器來控制對共享資源的訪問,如果計數器大於0,就允許訪問,如果等於0,就拒絕訪問。計數器累計的是“許可證”的數目,為了訪問某個資源。執行緒必須從訊號量獲取一個許可證。

通常在使用訊號量時,希望訪問共享資源的執行緒將嘗試獲取一個許可證,如果訊號量的計數器大於0,執行緒將獲取一個許可證並將訊號量的計數器減1,否則先執行緒將阻塞,直到獲取一個許可證;當執行緒不再需要共享資源時,將釋放鎖擁有的許可證,並將許可證的數量加1,如果有其他的執行緒正在等待許可證,那麼該執行緒將立刻獲取許可證。

另外,允許同時訪問的資源的程序數量是在建立訊號量時指定的,如果建立一個允許程序訪問的訊號量數目為1,則該訊號量就和互斥鎖的用法一樣。

Public Semaphore(int initialCount,int maximumCount)

initialCount指訊號量許可證的初始值,maximumCount為最大值

獲取許可證使用WaitOne()

不需要時釋放使用 public int Release();或者public int Release(int  releaseCount);

Semaphore與Mutex更像是兄弟,仍然與EventWaitHandle一脈不太親近:
Semaphore從機制上來說跟Mutex一樣屬於“鎖”而不是“通知”,因此跟Mutex一樣幾乎沒有“通知”的能力。
舉個不恰當但是很形象的例子,Semaphore就是一個可以多次進入的“Mutex”。Mutex永遠只允許一個執行緒擁有它,而Semaphore可以允許多個執行緒請求,因此Semaphore被用於管理一次可以允許多個執行緒進入併發訪問資源的情況。之所以說“不恰當”,是因為一旦允許多個執行緒訪問資源,那麼這時候的資源一定不是互斥資源,相應的程式碼段也不再是“臨界區”。你千萬不要以為我們在上一篇中提到的“糖罐”裡有多顆糖就叫做“資源池”(都說過了嘛一個糖罐一定是需要互斥訪問的),除非你有多個糖罐而不是多顆糖。
因為Semaphore與Mutex在請求數量上的不同,因此他們的執行緒相關性是不同的。這一點,Semaphore到跟EventWaitHandle一樣,它是執行緒無關的。也就是說對Semaphore地釋放者可以不定是Semaphore的擁有者。比如說我可以是消費者執行緒總使用WaitOne()請求執行緒池中的資源從來不需要釋放,而生產者總是Release執行緒池中的資源而從來不請求。

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

using System.Threading;

namespace MyTTCon
{
    class mythread
    {
        public Thread thrd;
        //建立一個可授權2個許可證的訊號量,且初始值為2
        static Semaphore sem = new Semaphore(2, 2);

        public mythread(string name)
        {
            thrd = new Thread(this.run);
            thrd.Name = name;
            thrd.Start();
        }
        void run()
        {
            Console.WriteLine(thrd.Name + "正在等待一個許可證……");
            //申請一個許可證
            sem.WaitOne();
            Console.WriteLine(thrd.Name + "申請到許可證……");
            for (int i = 0; i < 4; i++)
            {
                Console.WriteLine(thrd.Name + ": " + i);
                Thread.Sleep(10000);
            }
            Console.WriteLine(thrd.Name + " 釋放許可證……");
            //釋放
            sem.Release();
        }
    }

    class mysemaphore
    {
        public static void Main()
        {
            mythread mythrd1 = new mythread("Thrd #1");
            mythread mythrd2 = new mythread("Thrd #2");
            mythread mythrd3 = new mythread("Thrd #3");
            mythread mythrd4 = new mythread("Thrd #4");
            mythrd1.thrd.Join();
            mythrd2.thrd.Join();
            mythrd3.thrd.Join();
            mythrd4.thrd.Join();
        }
    }
}