【需求说明】
生产者消费者问题
• 一个大小为3的缓冲区,初始为空
• 2个生产者
– 随机等待一段时间,往缓冲区添加数据,
– 若缓冲区已满,等待消费者取走数据后再添加
– 重复6次
• 3个消费者
– 随机等待一段时间,从缓冲区读取数据
– 若缓冲区为空,等待生产者添加数据后再读取
– 重复4次
说明:
• 显示每次添加和读取数据的时间及缓冲区的状态
【程序代码】
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace ProducerAndCustomer { class Program { static void Main(string[] args) { //写入线程个数 int threadWriteNum = 2; //读取线程个数 int threadReadNum = 3; //创建缓冲区对象 Buffer buffer = new Buffer(); //创建写入线程 Thread[] threadsWrite = new Thread[threadWriteNum]; for (int i = 0; i < threadsWrite.Length; i++) { threadsWrite[i] = new Thread(new ThreadStart(buffer.Write)); threadsWrite[i].Name = "W" + (i + 1).ToString(); } //创建读取线程 Thread[] threadsRead = new Thread[threadReadNum]; for (int i = 0; i < threadsRead.Length; i++) { threadsRead[i] = new Thread(new ThreadStart(buffer.Read)); threadsRead[i].Name = "R" + (i + 1).ToString(); } buffer.PrintInitInfo(); //让线程开始运行 for (int i = 0; i < threadsWrite.Length; i++) threadsWrite[i].Start(); for (int i = 0; i < threadsRead.Length; i++) threadsRead[i].Start(); //等到线程运行完毕后再结束主线程 for (int i = 0; i < threadsWrite.Length; i++) threadsWrite[i].Join(); for (int i = 0; i < threadsRead.Length; i++) threadsRead[i].Join(); } } class Buffer { private object thisLock = new object(); private Queue<int> list = new Queue<int>(); //缓冲区大小 private int bufferNum = 3; //每个线程写入次数 private int writeTotalNum = 6; //每个线程读取次数 private int readTotalNum = 4; /// <summary> /// 打印初始化信息 /// </summary> public void PrintInitInfo() { Console.WriteLine("缓冲区大小:{0}.", bufferNum); Console.WriteLine("2个生产者,分别写入6次."); Console.WriteLine("3个消费者,分别读取4次."); Console.WriteLine(); } /// <summary> /// 往缓冲区里写入文件 /// </summary> public void Write() { //初始化写入次数 = 0 int writedNum = 0; //如果写入次数 < 设定写入次数6 while (writedNum < writeTotalNum) { //!先加锁,再判断。 如果这句放在if后面,则会出错 lock (this) { //判断缓冲区是否还有空位子 if (list.Count < bufferNum) { //模拟写入等待,随机等待一段时间 waitRandomTime(); //写入一个编号 list.Enqueue(writedNum); //更新统计信息 writedNum++; //打Log printCurrentTime(); Console.Write("Thread: " + Thread.CurrentThread.Name + " "); Console.WriteLine("写入 缓冲区文件数{0}.", list.Count); } else { //如果没有空位子,则等待 } } } //打Log printCurrentTime(); Console.WriteLine("Thread: " + Thread.CurrentThread.Name + " 写入完毕."); } /// <summary> /// 从缓冲区里读取文件 /// </summary> public void Read() { //初始化每个线程读出次数 = 0 int readedNum = 0; //如果读出次数 < 设定读出次数4 while (readedNum < readTotalNum) { //!先加锁,再判断。 如果这句放在if后面,则会出错 lock (this) { //首先判断缓冲区中是否有文件 if (list.Count > 0) { //模拟读取等待,随机等待一段时间 waitRandomTime(); //读取编号 list.Dequeue(); //更新信息 readedNum++; //打Log printCurrentTime(); Console.Write("Thread: " + Thread.CurrentThread.Name + " "); Console.WriteLine("读出 缓冲区文件数{0}.", list.Count); } else { //如果没有文件可以读取,则等待 } } } //打Log printCurrentTime(); Console.WriteLine("Thread: " + Thread.CurrentThread.Name + " 读出完毕."); } /// <summary> /// 随机等待一段时间 /// </summary> private void waitRandomTime() { Random ran = new Random(); Thread.Sleep(ran.Next(10, 1000)); } /// <summary> /// 打印当前时间。 /// </summary> private void printCurrentTime() { DateTime now = System.DateTime.Now; Console.Write(now.ToString() + " " + now.Millisecond.ToString() + "\t"); } } }
【运行截图】