亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

深入多線程之:深入生產者、消費者隊列分析

2020-01-24 03:19:41
字體:
來源:轉載
供稿:網友

上次我們使用AutoResetEvent實現了一個生產/消費者隊列。這一次我們要使用Wait和Pulse方法來實現一個更強大的版本,它允許多個消費者,每一個消費者都在自己的線程中運行。

我們使用數組來跟蹤線程。

Thread[] _workers;

通過跟蹤線程可以讓我們在所有的線程都結束后再結束我們的隊列任務。

每一個消費者線程都執行一個叫做Consume的方法,在一個for循環中,我們可以創建和啟動線程。例如:

復制代碼 代碼如下:

       public PCQueue(int workerCount)
        {
            _workers = new Thread[workerCount];
            for (int i = 0; i < workerCount; i++)
                (_workers[i] = new Thread(Consume)).Start();
        }

上次我們使用的是一個字符串來代表任務,這次我們使用Action委托,它的定義如下:

Public delegate void Action();

為了表示一系列的任務,我們使用Queue<T> 集合,例如:

Queue<Action> _itemQ = new Queue<Action>();

在我們調用生產(EnqueueItem)和消費(Consume)方法前,還是完整的看一看代碼吧:

復制代碼 代碼如下:

class PCQueue
    {
        readonly object _locker = new object();
        Thread[] _workers;
        Queue<Action> _itemQ = new Queue<Action>(); //保存任務的隊列
        public PCQueue(int workerCount)
        {
            _workers = new Thread[workerCount];
            for (int i = 0; i < workerCount; i++)
                (_workers[i] = new Thread(Consume)).Start();
        }

        public void Shutdown(bool waitForWorkers)
        {
           //為每一個線程插入一個null item,可以是每一個worker 退出
            foreach (Thread worker in _workers)
                EnqueueItem(null);

           //等待所有的線程退出。
            if (waitForWorkers)
                foreach (Thread worker in _workers)
                    worker.Join();
        }

        public void EnqueueItem(Action item)
        {
            lock (_locker)
            {
                _itemQ.Enqueue(item);
                Monitor.Pulse(_locker); //通知等待隊列中的線程
            }
        }

        void Consume()
        {
            while (true)
            {
                Action item;
                lock (_locker)
                {
                    while (_itemQ.Count == 0)
                    {
                        Monitor.Wait(_locker); //釋放鎖,并阻止當前線程,直到其他線程發送pulse信號。                    }
                    item = _itemQ.Dequeue();
                }

                if (item == null) return; //退出的信號
                item();
            }
        }
    }


我們可以有一個退出策略,插入一個null item作為consumer退出的信號。如果我們想要快速的退出,可以使用一個獨立的”cancel” 標記,因為我們支持多個consumers,所以我們必須為每一個consumer插入一個null item。

下面是Main方法。使用兩個consumer線程,然后讓這兩個consumers執行10個委托。

復制代碼 代碼如下:

public static void Main()
        {
            PCQueue q = new PCQueue(2);
            Console.WriteLine("Enqueuing 10 items...");

            for (int i = 0; i < 10; i++)
            {
                int itemNumber = i;
                q.EnqueueItem(() =>
                    {
                        Thread.Sleep(1000); //模擬耗時的工作
                        Console.WriteLine(" Task " + itemNumber);
                    });
            }

            q.Shutdown(true); //等待關閉
            Console.WriteLine();
            Console.WriteLine("Workers complete!");
        }

下面讓我們細致的看一看EnqueueItem方法:

復制代碼 代碼如下:

public void EnqueueItem(Action item)
        {
            lock (_locker)
            {
                _itemQ.Enqueue(item);
                Monitor.Pulse(_locker); //通知等待隊列中的線程
            }
        }

因為我們的隊列_itemQ被多線程環境使用,因此在對_itemQ進行讀取的時候需要加鎖lock.

因為我們插入了一個新的任務,我們必須修改阻塞條件,也就是調用pulse方法,來喚醒調用了wait方法的線程。


出于對效率的考慮,當插入一個Item的時候使用Pulse來代替PulseAll方法,因為大部分時候每一個Item只需要一個consumer來執行。如果你有一個冰淇淋,你不可能叫30個睡眠的孩子都起來吃它,同樣,對于一個item,同時喚醒30個consumers一點好處都沒有。


讓我們再看看Consumer方法。

我們希望當沒什么事情做的時候,線程阻塞就可以了,換句話說,隊列中沒有item的時候,線程就應該阻塞。因此我們的阻塞條件是_itemQ.Count ==0;

復制代碼 代碼如下:

Action item;
                lock (_locker)
                {
                    while (_itemQ.Count == 0)
                    {
                        Monitor.Wait(_locker); //釋放鎖,并阻止當前線程,直到其他線程發送pulse信號。                    }
                    item = _itemQ.Dequeue();
                }

                if (item == null) return; //退出的信號
                item();


while循環退出的時候也意味著_itemQ 至少有一個item。我們必須在釋放鎖之前調用你哦個dequeue方法來獲取item,考慮下下面的代碼:
復制代碼 代碼如下:

lock (_locker)
                {
                    while (_itemQ.Count == 0)
                    {
                        Monitor.Wait(_locker); //釋放鎖,并阻止當前線程,直到其他線程發送pulse信號。                    }
                }
                //現在在這里可能被搶占,_itemQ可能被修改
                lock (_locker)
                {
                    item = _itemQ.Dequeue();
                }

在item被Dequeued后,我們就應該立即釋放鎖了,如果我們在執行task的時候,一直持有鎖,則會沒有必要的阻塞其他線程來獲取任務。


Wait Timeouts

在調用Wait方法的時候可以傳遞一個毫秒或Timespan的時間來設置超時。如果Wait超時了,那么Wait方法就會返回false。

帶有超時功能的Wait方法的主要步驟:

    釋放鎖。
    阻塞 直到 pulsed 或者超時。
    重新獲取鎖。

超時就好像CLR 在超時到了的時候自動的調用了 pulse方法一樣。

下面是使用超時的Wait的主要代碼:

         lock(_locker)

         while(<阻塞條件>)

                   Monitor.Wait(_locker,<超時時間>);


Monitor.Wait 方法返回一個bool值來代表是調用了pulse還是已經超時了。

如果是true: 代表調用了pulse。

如果是false:代表超時了。

這對記錄日志很有用。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩欧美成人区| 亚洲影院色无极综合| 欧美xxxx18国产| 黄色精品一区二区| 日韩国产精品一区| 国产成人精品优优av| 久久久噜久噜久久综合| 亚洲曰本av电影| 国产日本欧美一区二区三区在线| 91免费福利视频| 18性欧美xxxⅹ性满足| 国产成人久久精品| 久久久精品在线观看| 亚洲aaa激情| 午夜剧场成人观在线视频免费观看| 欧美wwwwww| 国产中文字幕91| 欧美性理论片在线观看片免费| 91高清免费视频| 国产精品久久激情| 国产视频精品一区二区三区| 日本久久久久久久久| 久久久久久久久久亚洲| 国产精品久久久一区| 欧美日韩午夜视频在线观看| 国产在线精品成人一区二区三区| 啪一啪鲁一鲁2019在线视频| 久久久免费观看视频| 成人黄色免费片| 视频在线观看一区二区| 欧美成人剧情片在线观看| 国产成人精品午夜| 国产精品白丝jk喷水视频一区| 久久久久久成人精品| 日韩精品极品视频免费观看| 国产精品扒开腿做爽爽爽男男| 欧美日韩国内自拍| 欧美精品18videosex性欧美| 97视频免费看| 高清欧美一区二区三区| 精品久久久久久中文字幕| 日韩精品在线免费观看视频| 国产精品视频一区国模私拍| 成人美女av在线直播| 国产亚洲一区二区在线| 欧美日韩国产综合新一区| 亚洲精品小视频在线观看| 狠狠躁天天躁日日躁欧美| 亚洲精品国产品国语在线| 久久国内精品一国内精品| 日韩在线视频免费观看| 热久久免费视频精品| 亚洲欧美日韩精品久久亚洲区| 国产精品对白刺激| 久久天天躁狠狠躁夜夜躁| 久久777国产线看观看精品| 爱福利视频一区| 欧美日韩中文字幕综合视频| 日本精品久久电影| 欧美亚洲国产日韩2020| 国产欧美精品一区二区三区-老狼| 91在线无精精品一区二区| 成人免费观看网址| 91久久精品日日躁夜夜躁国产| 欧美亚洲视频在线看网址| 国产成人久久久| 欧美老女人bb| 欧美精品在线播放| 91中文字幕一区| 高清一区二区三区四区五区| 日韩中文字幕欧美| 国产精品专区h在线观看| 伊人久久精品视频| 久久最新资源网| 久久久久久久久久亚洲| 久久人人爽人人爽爽久久| 北条麻妃一区二区在线观看| 日韩免费观看视频| 久久视频中文字幕| 久久精品一本久久99精品| 91手机视频在线观看| 国产日产欧美精品| 亚洲自拍小视频免费观看| 2019中文字幕全在线观看| 亚洲白拍色综合图区| 欧美日韩在线视频首页| 久久好看免费视频| 欧美最猛性xxxxx免费| 正在播放亚洲1区| 亚洲国产精品久久久久秋霞蜜臀| 亚洲人成网站免费播放| 成人av电影天堂| 久久99国产综合精品女同| 国产伦精品一区二区三区精品视频| 国模叶桐国产精品一区| 在线观看欧美日韩| 欧美激情一级精品国产| 国产精品久久久久久久一区探花| 中文字幕综合在线| 在线播放亚洲激情| 国产精品色婷婷视频| 亚洲精品欧美一区二区三区| 欧美日韩一区二区免费在线观看| 国产一区二区三区四区福利| 亚洲欧美制服第一页| 久久综合色88| 国产一区二区黑人欧美xxxx| 一区二区三区四区视频| 97香蕉超级碰碰久久免费软件| 欧美性色视频在线| 在线播放日韩欧美| 亚洲人成电影网| 午夜精品福利电影| 伊人青青综合网站| 日韩欧美国产激情| 亚洲va国产va天堂va久久| 中文字幕亚洲图片| 亚洲精品久久久久国产| 日韩欧美国产高清91| 97香蕉超级碰碰久久免费软件| 精品日本美女福利在线观看| 激情懂色av一区av二区av| 91精品视频在线看| 亚洲午夜未满十八勿入免费观看全集| 欧美在线欧美在线| 久久久久久久国产精品| 欧美有码在线观看| 欧美天堂在线观看| 久久电影一区二区| 久久久久久999| 亚洲国产精品成人精品| 日韩日本欧美亚洲| 欧美性猛交xxxx免费看漫画| 欧美日韩国产123| 国产精品91久久| 日韩欧美中文在线| 久久久久久久久久久久av| 中文字幕亚洲欧美| 国产精品视频成人| 亚洲午夜激情免费视频| 亚洲美女免费精品视频在线观看| 国产a∨精品一区二区三区不卡| 国产成+人+综合+亚洲欧洲| 正在播放亚洲1区| 精品亚洲男同gayvideo网站| 中文字幕亚洲欧美日韩2019| 日韩在线视频观看正片免费网站| 中文字幕无线精品亚洲乱码一区| 国产日产久久高清欧美一区| 欧美性生交大片免网| 九九视频直播综合网| 日韩女优人人人人射在线视频| 国产欧美婷婷中文| 日韩精品在线观| 日韩欧美在线视频日韩欧美在线视频| 成人网在线免费看| 欧美日本精品在线| 久久好看免费视频| 最新日韩中文字幕| 日韩视频永久免费观看| 亚洲视频一区二区三区| 亚洲美女精品成人在线视频| 麻豆国产va免费精品高清在线| 91精品视频在线免费观看|