C#多线程的同步与通信
c#中使用lock和monitor控制多线程对资源的使用,最常见的生产者和消费者问题就是多线程同步和通信的经典例子。了解c#多线程的同步与通信。
一、关于lock和monitor
lock可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其它线程必须等待。格式定义如下:
lock(expression) statement_block
expression代表要跟踪的对象,通常是引用。一般地,如果想保护一个类的实例,使用this;如果保护一个静态变量(如互斥代码段在一个静态方法内部),使用类名就可以了。而statement_block就是互斥段的代码。
monitor用于多线程公用一个对象时使线程共享资源的方案。monitor必须和一个具体的对象相关联。
二、生产者和消费者问题
假设两个线程同时维护一个队列,如果一个线程对队列中更新元素,而另外一个线程从队列中获取元素,那么我们称更新元素的线程为生产者,称获取元素的线程为消费者。
1、被操作对象
/// <summary>; /// 被操作对象 /// </summary>; public class counter { //更新和读取的数字 private int numberofcounter; //读操作可执行标记,可以防止死锁的发生 private bool readflag = false; public void read() { //锁定后,其它读操作等待这一次读操作完成 lock (this) { //第一次之行为flase,进入等待 if (!readflag) { try { //进入等待读,另一个线程写 monitor.wait(this); } catch (exception ex) { console.writeline(ex); } } console.writeline("消费(获取): {0}", numberofcounter); //重置,消费已经完成 readflag = false; monitor.pulse(this); } } public void write(int number) { //锁定后,其它写操作等待这一次写操作完成 lock (this) { //第一次readflag为flase,跳过执行下边的写 //如果当前正在读,等待读操作执行monitor.pulse if (readflag) { try { monitor.wait(this); } catch (exception ex) { console.writeline(ex); } } numberofcounter = number; console.writeline("生产(更新): {0}", numberofcounter); //重置,生产已经完成 readflag = true; //同步通过等待pulse来完成 monitor.pulse(this); } } }
2、生产者和消费者
/// <summary>; /// 生产者 /// </summary> public class counterwrite { counter counter; //生产者生产次数 int quantity = 1; public counterwrite(counter box, int request) { //构造函数 counter = box; quantity = request; } //生产者向操作对象更新信息 public void write() { for (int i = 1; i <= quantity; i++) counter.write(i); } } /// <summary> /// 消费者 /// </summary> public class counterread { counter counter; //生产者生产次数 int quantity = 1; public counterread(counter box, int request) { //构造函数 counter = box; quantity = request; } //消费者从操作对象中获取信息 public void read() { for (int i = 1; i <= quantity; i++) counter.read(); } }
3、线程操作
counter counter = new counter(); counterread read = new counterread(counter, 10); counterwrite write = new counterwrite(counter, 10); thread th1 = new thread(new threadstart(read.read)); thread th2 = new thread(new threadstart(write.write)); th1.start(); th2.start(); th1.join(); th2.join(); console.readline();
通过lock锁定counter对象的引用,初始readflag为false控制线程1等待读取:monitor.wait(this),
线程2写入,然后更改readflag,然后执行:monitor.pulse(this),通知等待队列中的线程请求对象状态已发生改变,
线程1锁定this,执行读操作,然后更改readflag,线程1和线程2交互执行写读的操作。
同时因为readflag的存在和交替更新,避免了死锁情况的发生。
上一篇: WebApi生成文档
下一篇: java设计模式--适配器模式