C#使用泛型隊(duì)列Queue實(shí)現(xiàn)生產(chǎn)消費(fèi)模式
如果把生產(chǎn)消費(fèi)想像成自動(dòng)流水生產(chǎn)線的話,生產(chǎn)就是流水線的物料,消費(fèi)就是某種設(shè)備對(duì)物料進(jìn)行加工的行為,流水線就是隊(duì)列。
現(xiàn)在,要寫(xiě)一個(gè)體現(xiàn)生產(chǎn)消費(fèi)模式的泛型幫助類,比如叫ProducerConsumer<T>。
該類肯定會(huì)維護(hù)一個(gè)有關(guān)生產(chǎn)、物料的Queue<T>類型的字段,還存在一個(gè)有關(guān)消費(fèi)、Action<T>類型的字段。
在ProducerConsumer類的構(gòu)造函數(shù)中,為Action<T>類型的字段賦值,并開(kāi)啟后臺(tái)有關(guān)消費(fèi)的線程。
ProducerConsumer類肯定存在一個(gè)進(jìn)隊(duì)列的方法,并且要保證在多線程情況下,同一時(shí)間只有一個(gè)生產(chǎn)或物料進(jìn)入隊(duì)列。
ProducerConsumer類還存在一個(gè)有關(guān)消費(fèi)的方法,并且保證在多線程情況下,同一時(shí)間只有一個(gè)生產(chǎn)或物料出列,并消費(fèi)它。
另外,在生產(chǎn)或物料在出隊(duì)列的時(shí)候,可能會(huì)出現(xiàn)隊(duì)列中暫時(shí)沒(méi)有生產(chǎn)或物料的情況,這時(shí)候我們希望線程阻塞一下,這需要通過(guò)AutoResetEvent實(shí)現(xiàn)。AutoResetEvent的大致原理是:當(dāng)生產(chǎn)或物料進(jìn)入隊(duì)列的時(shí)候需要告訴AutoResetEvent一下,當(dāng)隊(duì)列中暫時(shí)沒(méi)有生產(chǎn)或物料的時(shí)候,也需要告訴AutoResetEvent,讓它來(lái)阻塞線程。
//有關(guān)生產(chǎn)消費(fèi)的泛型類 public class ProducerConsumer<T> { //用來(lái)存儲(chǔ)生產(chǎn)者的隊(duì)列 private readonly Queue<T> queue = new Queue<T>(); //鎖 private readonly object queueLocker = new object(); //消費(fèi)行為 private readonly Action<T> consumerAction; //出列的時(shí)候需要檢查隊(duì)列中是否有元素,如果沒(méi)有,需要阻塞 private readonly AutoResetEvent queueWaitHandle = new AutoResetEvent(false); public ProducerConsumer(Action<T> consumerAction) { if (consumerAction == null) { throw new ArgumentNullException("consumerAction"); } this.consumerAction = consumerAction; //后臺(tái)開(kāi)啟一個(gè)線程開(kāi)始消費(fèi)生產(chǎn)者 new Thread(this.ConsumeItems){IsBackground = true}.Start(); } //進(jìn)列 public void Enqueue(T item) { //確保同一時(shí)間只有一個(gè)生產(chǎn)者進(jìn)列 lock (queueLocker) { queue.Enqueue(item); //每次進(jìn)列都要設(shè)置AutoResetEvent事件 this.queueWaitHandle.Set(); } } //消費(fèi)動(dòng)作 private void ConsumeItems() { while (true) { T nextItem = default(T); //標(biāo)志,確認(rèn)隊(duì)列中的生產(chǎn)者是否存在 bool doesItemExist; //確保同一時(shí)間只有一個(gè)生產(chǎn)者出列 lock (this.queueLocker) { //先確認(rèn)隊(duì)列中的生產(chǎn)者是否存在 doesItemExist = this.queue.Count > 0; if (doesItemExist) { nextItem = this.queue.Dequeue(); } } //如果生產(chǎn)者存在,才消費(fèi)生產(chǎn)者 if (doesItemExist) { this.consumerAction(nextItem); } else//否則的話,再等等下一個(gè)隊(duì)列中的生產(chǎn)者 { this.queueWaitHandle.WaitOne(); } } } }
客戶端,針對(duì)多線程情形。
class Program { static void Main(string[] args) { //實(shí)例化一個(gè)int類型的生產(chǎn)消費(fèi)實(shí)例 var producerConsumer = new ProducerConsumer<int>(i => Console.WriteLine("正在消費(fèi)" + i)); Random random = new Random(); //開(kāi)啟進(jìn)隊(duì)列線程 var t1 = new Thread(() => { for (int i = 0; i < 100; i++) { producerConsumer.Enqueue(i); Thread.Sleep(random.Next(0,5)); } }); var t2 = new Thread(() => { for (int i = 0; i > -100; i--) { producerConsumer.Enqueue(i); Thread.Sleep(random.Next(0, 5)); } }); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Thread.Sleep(50); Console.ReadKey(); } }
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
C#中的WebRequest與WebResponse抽象類、DNS靜態(tài)類、Ping類介紹
這篇文章介紹了C#中的WebRequest與WebResponse抽象類、DNS靜態(tài)類、Ping類,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05WPF自定義控件實(shí)現(xiàn)ItemsControl魚(yú)眼效果
這篇文章主要為大家詳細(xì)介紹了WPF如何通過(guò)自定義控件實(shí)現(xiàn)ItemsControl魚(yú)眼效果,文中的示例代碼講解詳細(xì),需要的可以參考一下2024-01-01C#實(shí)現(xiàn)文件上傳下載Excel文檔示例代碼
這篇文章主要介紹了C#實(shí)現(xiàn)文件上傳下載Excel文檔示例代碼,需要的朋友可以參考下2017-08-08C#對(duì)接阿里云IOT平臺(tái)進(jìn)行設(shè)備開(kāi)發(fā)
這篇文章介紹了C#對(duì)接阿里云IOT平臺(tái)進(jìn)行設(shè)備開(kāi)發(fā),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析
這篇文章主要介紹了C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析,以實(shí)例形式較為詳細(xì)的講述了.NET Framework里面提供的三種Timer具體用法,需要的朋友可以參考下2014-10-10