- // @ 来源于挽留刀的技术系列文章-C#的多线程机制探索
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- namespace MutiThread
- {
- /* 每个线程都有自己的资源,但是代码区是共享的,即每个线程都
- * 可以执行相同的函数。但是多线程环境下,可能带来的问题就是
- * 几个线程同时执行一个函数,导致数据的混乱,产生不可预料的
- * 结果,因此我们必须避免这种情况的发生。这是线程同步的一个
- * 例子,解决了多线程应用程序中可能出现的大问题,只要领悟
- * 了解决线程间冲突的基本方法,很容易把它应用到比较复杂的程
- * 序中去。*/
- /* 首先生产者(添加元素的线程)生产了一个值,而同一时刻消费者
- * 处于等待状态,直到收到生产者的“脉冲(Pulse)”通知它生产已经
- * 完成,此后消费者(读取元素的线程)进入消费状态,而生产者开始
- * 等待消费者完成操作后将调用Monitor.Pulese()发出的“脉冲”。*/
- /// <summary>
- /// 要被操作的数据对象类
- /// </summary>
- public class Cell
- {
- int cellContents; // Cell对象里边的内容
- bool readerFlag = false; // 状态标志,为true时可以读取,为false则正在写入
- /// <summary>
- /// 读取cellContents
- /// </summary>
- /// <returns></returns>
- public int ReadFromCell()
- {
- // Lock标记代码临界区,如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
- lock (this)
- {
- if (!readerFlag) // 如果正在写入,不能读取
- {
- try
- {
- // Wait释放对象上的锁并阻止当前线程,直到它重新获取该锁。
- // 等待WriteToCell方法中调用Monitor.Pulse()方法
- Monitor.Wait(this);
- }
- catch (SynchronizationLockException e)
- {
- Console.WriteLine(e);
- }
- catch (ThreadInterruptedException e)
- {
- Console.WriteLine(e);
- }
- }
- Console.WriteLine("Consume: {0}", cellContents);
- readerFlag = false; // 重置readerFlag标志,表示消费行为已经完成
- // Pulse向等待线程发送信号,通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁
- Monitor.Pulse(this); // 通知WriteToCell()方法(该方法在另外一个线程中执行,等待中)
- }
- return cellContents;
- }
- /// <summary>
- /// 写入cellContents
- /// </summary>
- /// <param name="n"></param>
- public void WriteToCell(int n)
- {
- lock (this)
- {
- if (readerFlag) // 如果正在读取,不能写入
- {
- try
- {
- Monitor.Wait(this);
- }
- catch (SynchronizationLockException e)
- {
- // 当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用
- Console.WriteLine(e);
- }
- catch (ThreadInterruptedException e)
- {
- // 当线程在等待状态的时候中止
- Console.WriteLine(e);
- }
- }
- cellContents = n;
- Console.WriteLine("Produce: {0}", cellContents);
- readerFlag = true;
- Monitor.Pulse(this); // 通知另外一个线程中正在等待的ReadFromCell()方法
- }
- }
- }
- /// <summary>
- /// 生产者
- /// </summary>
- public class CellProd
- {
- Cell cell; // 被操作的Cell对象
- int quantity = 1; // 生产者生产次数,初始化为1
- public CellProd(Cell box, int request)
- {
- // 构造函数
- cell = box;
- quantity = request;
- }
- public void ThreadRun()
- {
- for (int looper = 1; looper <= quantity; looper++)
- cell.WriteToCell(looper); // 生产者向操作对象写入信息
- }
- }
- /// <summary>
- /// 消费者
- /// </summary>
- public class CellCons
- {
- Cell cell;
- int quantity = 1;
- public CellCons(Cell box, int request)
- {
- cell = box;
- quantity = request;
- }
- public void ThreadRun()
- {
- int valReturned;
- for (int looper = 1; looper <= quantity; looper++)
- valReturned = cell.ReadFromCell(); // 消费者从操作对象中读取信息
- }
- }
- /// <summary>
- /// 入口
- /// </summary>
- public class MonitorSample
- {
- public static void Main(String[] args)
- {
- int result = 0;
- // 一个标志位,如果是0表示程序没有出错,如果是1表明有错误发生
- Cell cell = new Cell();
- // 下面使用cell初始化CellProd和CellCons两个类,生产和消费次数均为20次
- CellProd prod = new CellProd(cell, 20);
- CellCons cons = new CellCons(cell, 20);
- // 生产者线程
- Thread producer = new Thread(new ThreadStart(prod.ThreadRun));
- // 消费者线程
- Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));
- // 生产者线程和消费者线程都已经被创建,但是没有开始执行
- try
- {
- producer.Start();
- consumer.Start();
- producer.Join();
- consumer.Join();
- Console.ReadLine();
- }
- catch (ThreadStateException e)
- {
- // 当线程因为所处状态的原因而不能执行被请求的操作
- Console.WriteLine(e);
- result = 1;
- }
- catch (ThreadInterruptedException e)
- {
- // 当线程在等待状态的时候中止
- Console.WriteLine(e);
- result = 1;
- }
- // 尽管Main()函数没有返回值,但下面这条语句可以向父进程返回执行结果
- // 获取或设置进程的退出代码
- Environment.ExitCode = result;
- }
- }
- }
多线程进阶代码二
最新推荐文章于 2023-07-06 13:57:28 发布