C#之使用AutoResetEvent實現線程的順序執行

前幾天一朋友問我如何實現線程的順序執行,說真的,雖然看過CLR這本書,也把線程部分拜讀了兩遍,可是這個問題出來以後仍是沒有一個思路。今天在搜索資料的時候無心中再次看到AutoResetEvent這個東西,固然我知道它是和線程有關,用於處理線程切換之類的(可能在測試Demo以前理解有誤),因而決定用AutoResetEvent來處理上面的問題。多線程

這裏以園區一個園友的例子來講明,這個例子就是 買書--》付款--》拿書這個過程,該過程會持續n(經過變量設置)次,而且每一次都要按照順序執行,有可能有同窗會疑問,直接Sleep不就行了,幹嗎非要多個線程,若是處理某一個環節的時間太久或者是業務複雜,那麼整個程序就直接未響應了,因此這裏加入多線程來保證程序的響應。測試

class Program
    {
        //循環次數
        const int numIterations = 10;
        //買書
        static AutoResetEvent buyResetEvent = new AutoResetEvent(false);
        //付款
        static AutoResetEvent payResetEvent = new AutoResetEvent(false);
        //取書
        static AutoResetEvent getBookEvent = new AutoResetEvent(false);
       //循環的次數
        static int number;
        static void Main(string[] args)
        {
            //付款線程
            Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));
            payMoneyThread.Name = "付錢線程";

            //取書線程
            Thread getBookThread = new Thread(new ThreadStart(GetBookProc));
            getBookThread.Name = "取書線程";

            payMoneyThread.Start();
            getBookThread.Start();

            for (int i = 1; i <= numIterations; i++)
            {
                Console.WriteLine("買書線程:數量{0}", i);
                number = i;
                //容許付款線程等待
                payResetEvent.Set();
                //禁止買書線程等待
                buyResetEvent.WaitOne();
            }
            Console.Read();
        }

        static void PayMoneyProc()
        {
            while (true)
            {
                //等待付款
                payResetEvent.WaitOne();
                Console.WriteLine("{0}:數量{1}", Thread.CurrentThread.Name, number);
                //容許取書線程等待
                getBookEvent.Set();
            }
        }
        static void GetBookProc()
        {
            while (true)
            {
                //等待付款
                getBookEvent.WaitOne();      
                Console.WriteLine("{0}:數量{1}", Thread.CurrentThread.Name, number);
                Console.WriteLine("------------------------------------------");
                //容許買書線程等待(到這一步一個完整的買書流程就執行結束了,徹底按照買書--》付款--》取書的流程)
                buyResetEvent.Set();
            }
        }
    }

上述代碼不復雜,可是有幾個關鍵的對象和方法,接下來詳細進行說明。spa

1.分別定義了買書、付款、拿書三個AutoResetEvent,注意定義的時候傳入了false,這也AutoSet默認是不可用的,須要手動調用Set方法才能夠呢。該對象是決定是否能WaitOne一個請求的關鍵,當AutoResetEvent.Set執行則可使用AutoResetEvent.WaitOne進行一個等待請求,若是再有WaitOne請求,則要繼續等待Set的執行;.net

2.先看for循環,在循環中咱們使用payResetEvent.Set()這句代碼,這也PayThread中的WaitOne請求就能夠得到批准(下文有介紹),同時咱們又加上了buyResetEvent.WaitOne()(這樣在上一次購買流程結束以前,新的一次流程是不能夠執行的,這也就是咱們的最大問題,保證線程按照順序執行);線程

3.定義了付款和拿書的Thread,而且在方法內都是While循環,該循環主要是爲了能夠將咱們的過程進行屢次,畢竟線程只會執行一遍嘛。固然這個不是重點,重點是While中咱們的操做,先看PayThrea的操做,先調用payResetEvent.WaitOne()請求一個等待操做,固然能夠立馬執行,由於在 2 中咱們說了for中是調用了payResetEvent.Set()操做,這樣就能夠直接獲得一個請求響應,輸出關鍵信息,而後又到了重點,咱們調用了getBookEvent.Set(),這是爲何呢,由於付款不成功是不能夠拿書走的啊,那樣就是偷盜了。注意、注意、注意,重要的話說三遍,GetBookThread操做中也有一個waitOne請求,但是爲何不會執行呢,由於沒有Set呢,咱們初始化AutoResetEvent的時候咱們設置的是false,這樣默認就不能夠獲得一個請求,必須手動調用Set才能夠,因爲在PayMoneyThread的最後一行代碼中咱們調用了getBookEvent.Set(),這樣getBookEvent.WaitOne就可用了。在GetBookThread中依次輸出關鍵信息,最後一行代碼又來了,再次調用了一個AutoResetEvent.Set(),沒錯就是買書的對象,由於到了這一步完整的買書流程就結束了,能夠再次買書了啊啊啊啊啊啊,能夠買書了,好開心啊。而後再次回到for循環中的最後一行代碼,buyResetEvent.Wait()此時就復活了,開始第好幾回的買書流程。code

運行截圖以下(絕對真實,毫無PS):對象

好了,退朝,有事改天上朝再議。blog

 

Update:鑑於你們對這個使用方式有不一樣的建議,另外.net的版本都4.6了,因此從新使用Task的方式進行了更新,歡迎繼續拍磚.get

 

 static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Task buyTask = Task.Factory.StartNew(() =>
                {
                    BuyBook();
                }).ContinueWith((state) =>
                {
                    PayMoney();
                }).ContinueWith((state) =>
                {
                    TakeBook();
                });
                Task.WaitAll(buyTask);
                Console.WriteLine();
            }

            Console.Read();
        }

        private static void BuyBook()
        {
            Console.WriteLine("書太多了,挑花眼了");
        }

        private static void PayMoney()
        {
            Console.WriteLine("先付錢才能取書哦");
        }

        private static void TakeBook()
        {
            Console.WriteLine("取書嘍");
        }
相關文章
相關標籤/搜索