internal class Program { //最多容纳50个橘子每个框 static readonly int MAX = 50; //两个框 static List<ConcurrentQueue<Orange>> Queues = new List<ConcurrentQueue<Orange>>(); //记录空闲的框 static List<int> QidxBags = new List<int>(); static int MaxO = 1000; //最多摘1000个橘子 static readonly object Sync = new object(); static readonly object Sync2 = new object(); //比起AutoResetEvent,可以唤起多个线程,如果说小孩一次拿多个橘子,而不是一个, //这种方式比AutoResetEvent有优势,因为AutoResetEvent只唤醒一个线程。 static ManualResetEvent MResetEvent = new ManualResetEvent(false); static void Main(string[] args) { Queues.Add(new ConcurrentQueue<Orange>()); Queues.Add(new ConcurrentQueue<Orange>()); for (int i = 0; i < Queues.Count; i++) { QidxBags.Add(i); } TaskProduceAndComsummer(); Console.ReadKey(); } static int GetQueuesIdx() { int idx = -1; int count = QidxBags.Count; if (count > 0) { return count; } return idx; } static bool IsEmpty() { foreach (var item in Queues) { if (item.Count >0) { return false; } } return true; } static bool IsFull() { foreach (var item in Queues) { if (item.Count < MAX) { return false; } } return true; } static void TaskProduceAndComsummer() { for (int i = 0; i < 5; i++) { string name = "工人_" + (i + 1); Task t = new Task(Produce, (object)(name)); t.Start(); } for (int i = 0; i < 3; i++) { string name = "小孩_" + (i + 1); Task t = new Task(Consumer, (object)(name)); t.Start(); } } static void Produce(object name) { while (true&&MaxO>0) { int count = -1; int iPos = -1; lock (Sync2) { count = GetQueuesIdx(); } if (count > 0&&!IsFull()) { bool refTaken = false; Monitor.Enter(Sync, ref refTaken); bool isPut = false; try { for (int i = 0; i < count; i++) { iPos = QidxBags[i]; var q = Queues[iPos]; if (q.Count < MAX) { QidxBags.Remove(iPos); q.Enqueue(Orange.GetOrange()); MaxO -= 1; Console.WriteLine(name + ":+摘了一个橘子,放入框【" + iPos + "】中"); Console.WriteLine("框一数量:{0},框二数量{1}", Queues[0].Count, Queues[1].Count); isPut = true; //唤醒小孩线程 MResetEvent.Set(); break; } } } finally { if (refTaken) { if (iPos > -1) { QidxBags.Add(iPos); } Monitor.Exit(Sync); if (!isPut) { Console.WriteLine("满了"); } } } } else { MResetEvent.WaitOne(); } } } static void Consumer(object name) { while (true) { int count = GetQueuesIdx(); int iPos = -1; if (count > 0&&!IsEmpty()) { bool refTaken = false; bool isPut = false; Monitor.Enter(Sync, ref refTaken); try { for (int i = 0; i < count; i++) { iPos = QidxBags[i]; var q = Queues[iPos]; if (q.Count >0) { QidxBags.Remove(iPos); Orange o = null; q.TryDequeue(out o); Console.WriteLine(name + ":+拿了一个橘子,从框【" + iPos + "】中"); Console.WriteLine("框一数量:{0},框二数量{1}", Queues[0].Count, Queues[1].Count); isPut = true; //框有容量了,可以放了,所以唤醒被阻塞得工人线程 MResetEvent.Set(); break; } } } finally { if (refTaken) { if (iPos > -1) { QidxBags.Add(iPos); } Monitor.Exit(Sync); if (!isPut) { Console.WriteLine("都空了"); } } } } else { MResetEvent.WaitOne();//阻塞 } } } } public class Orange { public static Orange GetOrange() { Random rand = new Random(); int t = rand.Next(10, 20); Thread.Sleep(t); return new Orange(); } }
部分结果: