C#的多线程机制探索(3.2)

 
C#的多线程机制探索(3.2)
2007-04-03 15:52
   下面是一个展示如何使用 lock 关键字和 Monitor 类来实现线程的同步和通讯的例子,也是一个典型的生产者与消费者问题。这个例程中,生产者线程和消费者线程是交替进行的,生产者写入一个数,消费者立即读取并且显示,我将在注释中介绍该程序的精要所在。用到的系统命名空间如下:
  using System;
  using System.Threading;
首先,我们定义一个被操作的对象的类 Cell ,在这个类里,有两个方法: ReadFromCell() WriteToCell 。消费者线程将调用 ReadFromCell() 读取 cellContents 的内容并且显示出来,生产者进程将调用 WriteToCell() 方法向 cellContents 写入数据。
  public class Cell
  {
   int cellContents; // Cell 对象里边的内容
   bool readerFlag = false; // 状态标志,为 true 时可以读取,为 false 则正在写入
   public int ReadFromCell( )
   {
     lock(this) // Lock 关键字保证了什么,请大家看前面对 lock 的介绍
     {
     if (!readerFlag)// 如果现在不可读取
     {
       try
       {
       file:// 等待 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; file:// 重置 readerFlag 标志,表示消费行为已经完成
     Monitor.Pulse(this); file:// 通知 WriteToCell() 方法(该方法在另外一个线程中执行,等待中)
     }
     return cellContents;
   }

   public void WriteToCell(int n)
   {
     lock(this)
     {
     if (readerFlag)
     {
       try
       {
       Monitor.Wait(this);
       }
       catch (SynchronizationLockException e)
       {
       file:// 当同步方法(指 Monitor 类除 Enter 之外的方法)在非同步的代码区被调用
       Console.WriteLine(e);
       }
       catch (ThreadInterruptedException e)
       {
       file:// 当线程在等待状态的时候中止
       Console.WriteLine(e);
       }
     }
     cellContents = n;
     Console.WriteLine("Produce: {0}",cellContents);
     readerFlag = true;
     Monitor.Pulse(this); file:// 通知另外一个线程中正在等待的 ReadFromCell() 方法
     }
   }
  }

   下面定义生产者 CellProd 和消费者类 CellCons ,它们都只有一个方法 ThreadRun() ,以便在 Main() 函数中提供给线程的 ThreadStart 代理对象,作为线程的入口。
  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); file:// 生产者向操作对象写入信息
   }
  }


  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( );// 消费者从操作对象中读取信息
   }
  }
然后在下面这个类 MonitorSample Main() 函数中我们要做的就是创建两个线程分别作为生产者和消费者,使用 CellProd.ThreadRun() 方法和 CellCons.ThreadRun() 方法对同一个 Cell 对象进行操作。
  public class MonitorSample
  {
   public static void Main(String[] args)
   {
     int result = 0; file:// 一个标志位,如果是 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)
     {
     file:// 当线程因为所处状态的原因而不能执行被请求的操作
     Console.WriteLine(e);
     result = 1;
     }
     catch (ThreadInterruptedException e)
     {
     file:// 当线程在等待状态的时候中止
     Console.WriteLine(e);
     result = 1;
     }
     // 尽管 Main() 函数没有返回值,但下面这条语句可以向父进程返回执行结果
     Environment.ExitCode = result;
   }
  }
大家可以看到,在上面的例程中,同步是通过等待 Monitor.Pulse() 来完成的。首先生产者生产了一个值,而同一时刻消费者处于等待状态,直到收到生产者的 脉冲 (Pulse)” 通知它生产已经完成,此后消费者进入消费状态,而生产者开始等待消费者完成操作后将调用 Monitor.Pulese() 发出的 脉冲 。它的执行结果很简单:
  Produce: 1
  Consume: 1
  Produce: 2
  Consume: 2
  Produce: 3
  Consume: 3
  ...
  ...
  Produce: 20
  Consume: 20

   事实上,这个简单的例子已经帮助我们解决了多线程应用程序中可能出现的大问题,只要领悟了解决线程间冲突的基本方法,很容易把它应用到比较复杂的程序中去
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值