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)在,要寫一個(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>類型的字段賦值,并開啟后臺(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í)沒有生產(chǎn)或物料的情況,這時(shí)候我們希望線程阻塞一下,這需要通過AutoResetEvent實(shí)現(xiàn)。AutoResetEvent的大致原理是:當(dāng)生產(chǎn)或物料進(jìn)入隊(duì)列的時(shí)候需要告訴AutoResetEvent一下,當(dāng)隊(duì)列中暫時(shí)沒有生產(chǎn)或物料的時(shí)候,也需要告訴AutoResetEvent,讓它來阻塞線程。
//有關(guān)生產(chǎn)消費(fèi)的泛型類
public class ProducerConsumer<T>
{
//用來存儲(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ì)列中是否有元素,如果沒有,需要阻塞
private readonly AutoResetEvent queueWaitHandle = new AutoResetEvent(false);
public ProducerConsumer(Action<T> consumerAction)
{
if (consumerAction == null)
{
throw new ArgumentNullException("consumerAction");
}
this.consumerAction = consumerAction;
//后臺(tái)開啟一個(gè)線程開始消費(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();
//開啟進(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();
}
}以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
c# 調(diào)用Surfer軟件,添加引用的具體操作方法
本篇文章主要是對(duì)c#中調(diào)用Surfer軟件,添加引用的具體操作方法進(jìn)行了介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01
unity實(shí)現(xiàn)簡(jiǎn)單貪吃蛇游戲
這篇文章主要為大家詳細(xì)介紹了unity實(shí)現(xiàn)簡(jiǎn)單貪吃蛇游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
C#短時(shí)間內(nèi)產(chǎn)生大量不重復(fù)的隨機(jī)數(shù)
在C#編程中,經(jīng)常會(huì)碰到產(chǎn)生隨機(jī)數(shù)的情況,并且是在短時(shí)間內(nèi)產(chǎn)生一組隨機(jī)數(shù)。如果這組隨機(jī)數(shù)中有大量重復(fù)的,則達(dá)不到我們的要求2013-02-02
解析C#多線程編程中異步多線程的實(shí)現(xiàn)及線程池的使用
這篇文章主要介紹了C#多線程編程中異步多線程的實(shí)現(xiàn)及線程池的使用,同時(shí)對(duì)多線程的一般概念及C#中的線程同步并發(fā)編程作了講解,需要的朋友可以參考下2016-03-03
asp.net core 使用 tensorflowjs實(shí)現(xiàn) face recognition的源代碼
tensorflowjs,在該項(xiàng)目中使用了ml5js這個(gè)封裝過的機(jī)器學(xué)習(xí)JavaScript類庫, 使用起來更簡(jiǎn)單,本文給大家分享asp.net core 使用 tensorflowjs實(shí)現(xiàn) face recognition的源代碼,需要的朋友參考下吧2021-06-06

