生產者消費者問題是一個著名的線程同步問題,該問題描述如下:有一個生產者在生產產品,這些產品將提供給若干個消費者去消費,為了使生產者和消費者能並發執行,在兩者之間設置一個具有多個緩沖區的緩沖池,生產者將它生產的產品放入一個緩沖區中,消費者可以從緩沖區中取走產品進行消費,顯然生產者和消費者之間必須保持同步,即不允許消費者到一個空的緩沖區中取產品,也不允許生產者向一個已經放入產品的緩沖區中再次投放產品。
首先來簡化問題,先假設生產者和消費者都只有一個,且緩沖區也只有一個。這樣情況就簡便多了。
第一.從緩沖區取出產品和向緩沖區投放產品必須是互斥進行的。可以用互斥鎖來完成。
第二.生產者要等待緩沖區為空,這樣才可以投放產品,消費者要等待緩沖區不為空,這樣才可以取出產品進行消費。並且由於有二個等待過程,所以要用二個事件或者信號量來控制。
在.net中,用Monitor可以同時達到以上兩者的效果。演示如下:
1 首先,聲明一個隊列:
_queue = new Queue<T>();
2 設置緩沖區大小:
int _maxQueueCount=1024;
3 用兩個變量來記錄生產者和消費者的數量:
int _consumersWaiting; int _producersWaiting;
4 生產者生產:
lock (_locker) { _queue.Enqueue(item); while (_queue.Count >= _maxQueueCount && !_isDisposed) { _producersWaiting++; Monitor.Wait(_locker); _producersWaiting--; } if (_consumersWaiting > 0) Monitor.PulseAll(_locker); }
生產者在隊列的長度大於緩沖區之后,釋放鎖並進入等待狀態,同時通知消費者。
5 消費者開始消費:
lock (_locker) { //消費所有數據 if (_producersWaiting > 0) Monitor.PulseAll(_locker); _consumersWaiting++; Monitor.Wait(_locker); _consumersWaiting--; }
消費者在消費完緩沖區所有數據之后,通知生產者,釋放鎖,並進入等待狀態。
這個時候,生產者重新得到鎖,並繼續生產。
生產者與消費者變會一直有序的交叉進行下去。
然后再對這個簡單生產者消費者問題加大難度。將消費者改成2個,緩沖池改成擁有4個緩沖區的大緩沖池。
請讀者自行研究解決辦法。
最后,關於生產者和消費者的問題,總結如下:
1.首先要考慮生產者與消費者對緩沖區操作時的互斥。
2.不管生產者與消費者有多少個,緩沖池有多少個緩沖區。都只有二個同步過程——分別是生產者要等待有空緩沖區才能投放產品,消費者要等待有非空緩沖區才能去取產品。
正確掌握生產者和消費者問題的解決辦法,為開發人員的一種基本素質之一。當然Coding依然是真正掌握的不二法門:)