- //一个同步程序,生产者向一个缓冲区(定义为三个字节)中写入数据,消费者从中提取数
- //据,如果缓冲区中没有数据,那么consumer只好wait,进入等待状态,当另一个线程(也就是
- //生产者)向缓冲区中写入数据猴,执行了Monitor.pulse,唤醒了consumer的等待,开始读取
- //数据.反之,当producer写入数据的时候,如果缓冲区已满,那么只好进入等待状态,当另一
- //个线程(也就是消费者)从中读取了数据,缓冲区有了空间,那么消费者执行
- //Monitor.pulse,唤醒生产者,继续写入数据.
- //程序使用了lock来锁定共享数据区,而不是使用Monitor.enter和Monitor.exit,因为你可
- //能很容易忘记enter后exit掉,而lock则是隐式的执行了exit,所以建议用lock.
- //当然,在程序执行的过程中,因为是线程,所以执行结果是不可再现的!!每次可能执行的顺
- //序有很多种!!
- //定义了四个类:
- //第一个类LetSynchronized,主要用来存取数据,并且在存取的时候,加上了共享锁.
- //第二个类Producer,生产者,调用一个LetSynchronized类的实例的setBuffer方法来存放
- //数据.
- //第三个类Consumer,消费者, 调用一个LetSynchronized类的实例的getBuffer方法来存放
- //数据.
- //第四个类ThreadStart,测试类,也是这个cs中的启动类,定义了LetSynchornized实例,然
- //后传递给了Producer和Consumer,然后定义了两个线程,线程启动的是Producer
- //的produce方法和Consumer的consume方法,最后启动这两个线程.
- using System;
- using System.Threading;
- //LetSynchronized用来存放和取出缓冲区变量
- public class LetSynchronized
- {
- private int[] buffer={-1,-1,-1};
- //定义了只有三个字节的缓冲区
- private int bufferCount=0;
- //确认缓冲区内已放数值的个数
- private int readLocation=0,writeLocation=0;
- //确定读写的位置
- public LetSynchronized()
- {
- }
- public int getBuffer()
- {
- lock(this)
- //加上了共享锁
- {
- if(bufferCount==0)
- {
- Console.WriteLine("缓冲区无数据,消费者无法读取");
- Monitor.Wait(this);
- }
- //判断如果缓冲区内无内容,则Consumer进入wait状态,并且释放对象锁
- int readValue=buffer[readLocation];
- bufferCount--;
- //已经从缓冲区读取了内容,所以bufferCount要进行自减.
- readLocation=(readLocation+1)%buffer.Length;
- //求余的目的是为了循环使用缓冲区
- Monitor.Pulse(this);
- //通知对象的第一个等待线程可以从WaitSleepJoin转换到Started状态.
- return readValue;
- //返回给consumer取出的数值
- }
- }
- public void setBuffer(int writeValue) //将数据放入缓冲区
- {
- lock(this)
- {//锁住共享数据区
- if(bufferCount==buffer.Length)
- {
- Console.WriteLine("缓冲区!");
- Monitor.Wait(this);
- }
- //如果缓冲区已满,那么进入waitsleepjoin状态
- buffer[writeLocation]=writeValue;
- //向缓冲区写入数据
- bufferCount++;
- //自加,代表缓冲区现在到底有几个数据
- writeLocation=(writeLocation+1)%buffer.Length;
- //用%实现缓冲区的循环利用
- Monitor.Pulse(this);
- //唤醒waitSleepJoin状态的进程,到started状态
- }//使用lock隐式的释放了共享锁
- }
- }
- public class Producer //生产者类,向缓冲区中放入数据
- {
- LetSynchronized shared;
- //定义了同步变量
- public Producer(LetSynchronized sharedLocation)
- {
- shared=sharedLocation;
- }
- //此处构造函数的作用是在启动类中调用Producer的时候,把启动类中定义的sharedLocation传过来
- public void produce()//定义生产过程
- {
- for(int count=1;count<=5;count++)
- {
- shared.setBuffer(count);
- Console.WriteLine("生产者向缓冲区中写入 "+ count);
- }
- //将数据放入缓冲区
- string name=Thread.CurrentThread.Name;
- //得到当前线程的名字
- Console.WriteLine(name+"done producing");
- //此线程执行完毕
- }
- }
- public class Consumer//定义消费者类
- {
- private int value;
- LetSynchronized shared;
- //定义同步变量
- public Consumer(LetSynchronized sharedLocation)
- {
- shared=sharedLocation;
- }
- //定义构造函数,负责传递启动类中的shared
- public void consume()
- {
- for(int count=1;count<=5;count++)
- {
- value=shared.getBuffer();
- Console.WriteLine("消费者从缓冲中读取了数据 "+value);
- }
- //从缓冲区中循环读取
- string name=Thread.CurrentThread.Name;
- //取得当前线程的名字
- Console.WriteLine(name+"done consuming");
- }
- }
- public class ThreadTest //设置为启动类
- {
- public static void Main()
- {
- LetSynchronized shared=new LetSynchronized();
- Producer producer1=new Producer(shared);
- Consumer consumer1=new Consumer(shared);
- //初始化了生产者和消费者,并且把shared参数传递了过去
- Thread producerThread = new Thread(new ThreadStart (producer1.produce));
- producerThread.Name="生产者";
- //定义了一个producerThread线程,new Thread是构造Thread
- //后面的那个new 则是启动一个新的线程,线程启动的方法是producer1.produce
- Thread consumerThread = new Thread(new ThreadStart (consumer1.consume));
- consumerThread.Name="消费者";
- //同上
- producerThread.Start();
- consumerThread.Start();
- //启动这两个线程
- }
C#生产者与消费者问题 线程同步
最新推荐文章于 2021-05-06 22:05:46 发布