多线程进阶代码二

来源:互联网 发布:skype无法连接到网络 编辑:程序博客网 时间:2024/05/17 05:18
  1. // @ 来源于挽留刀的技术系列文章-C#的多线程机制探索
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading;
  7. namespace MutiThread
  8. {
  9.     /* 每个线程都有自己的资源,但是代码区是共享的,即每个线程都
  10.      * 可以执行相同的函数。但是多线程环境下,可能带来的问题就是
  11.      * 几个线程同时执行一个函数,导致数据的混乱,产生不可预料的
  12.      * 结果,因此我们必须避免这种情况的发生。这是线程同步的一个
  13.      * 例子,解决了多线程应用程序中可能出现的大问题,只要领悟
  14.      * 了解决线程间冲突的基本方法,很容易把它应用到比较复杂的程
  15.      * 序中去。*/
  16.     /* 首先生产者(添加元素的线程)生产了一个值,而同一时刻消费者
  17.      * 处于等待状态,直到收到生产者的“脉冲(Pulse)”通知它生产已经
  18.      * 完成,此后消费者(读取元素的线程)进入消费状态,而生产者开始
  19.      * 等待消费者完成操作后将调用Monitor.Pulese()发出的“脉冲”。*/
  20.     /// <summary>
  21.     /// 要被操作的数据对象类
  22.     /// </summary>
  23.     public class Cell
  24.     {
  25.         int cellContents; // Cell对象里边的内容
  26.         bool readerFlag = false// 状态标志,为true时可以读取,为false则正在写入
  27.         /// <summary>
  28.         /// 读取cellContents
  29.         /// </summary>
  30.         /// <returns></returns>
  31.         public int ReadFromCell()
  32.         {
  33.             // Lock标记代码临界区,如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
  34.             lock (this)
  35.             {
  36.                 if (!readerFlag) // 如果正在写入,不能读取
  37.                 {
  38.                     try
  39.                     {
  40.                         // Wait释放对象上的锁并阻止当前线程,直到它重新获取该锁。
  41.                         // 等待WriteToCell方法中调用Monitor.Pulse()方法
  42.                         Monitor.Wait(this);
  43.                     }
  44.                     catch (SynchronizationLockException e)
  45.                     {
  46.                         Console.WriteLine(e);
  47.                     }
  48.                     catch (ThreadInterruptedException e)
  49.                     {
  50.                         Console.WriteLine(e);
  51.                     }
  52.                 }
  53.                 Console.WriteLine("Consume: {0}", cellContents);
  54.                 readerFlag = false;    // 重置readerFlag标志,表示消费行为已经完成
  55.                 // Pulse向等待线程发送信号,通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁
  56.                 Monitor.Pulse(this);   // 通知WriteToCell()方法(该方法在另外一个线程中执行,等待中)
  57.             }
  58.             return cellContents;
  59.         }
  60.         /// <summary>
  61.         /// 写入cellContents
  62.         /// </summary>
  63.         /// <param name="n"></param>
  64.         public void WriteToCell(int n)
  65.         {
  66.             lock (this)
  67.             {
  68.                 if (readerFlag) // 如果正在读取,不能写入
  69.                 {
  70.                     try
  71.                     {
  72.                         Monitor.Wait(this);
  73.                     }
  74.                     catch (SynchronizationLockException e)
  75.                     {
  76.                         // 当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用
  77.                         Console.WriteLine(e);
  78.                     }
  79.                     catch (ThreadInterruptedException e)
  80.                     {
  81.                         // 当线程在等待状态的时候中止 
  82.                         Console.WriteLine(e);
  83.                     }
  84.                 }
  85.                 cellContents = n;
  86.                 Console.WriteLine("Produce: {0}", cellContents);
  87.                 readerFlag = true;
  88.                 Monitor.Pulse(this);  // 通知另外一个线程中正在等待的ReadFromCell()方法
  89.             }
  90.         }
  91.     }
  92.     /// <summary>
  93.     /// 生产者
  94.     /// </summary>
  95.     public class CellProd
  96.     {
  97.         Cell cell; // 被操作的Cell对象
  98.         int quantity = 1; // 生产者生产次数,初始化为1 
  99.         public CellProd(Cell box, int request)
  100.         {
  101.             // 构造函数
  102.             cell = box;
  103.             quantity = request;
  104.         }
  105.         public void ThreadRun()
  106.         {
  107.             for (int looper = 1; looper <= quantity; looper++)
  108.                 cell.WriteToCell(looper); // 生产者向操作对象写入信息
  109.         }
  110.     }
  111.     /// <summary>
  112.     /// 消费者
  113.     /// </summary>
  114.     public class CellCons
  115.     {
  116.         Cell cell;
  117.         int quantity = 1;
  118.         public CellCons(Cell box, int request)
  119.         {
  120.             cell = box;
  121.             quantity = request;
  122.         }
  123.         public void ThreadRun()
  124.         {
  125.             int valReturned;
  126.             for (int looper = 1; looper <= quantity; looper++)
  127.                 valReturned = cell.ReadFromCell(); // 消费者从操作对象中读取信息
  128.         }
  129.     }
  130.     /// <summary>
  131.     /// 入口
  132.     /// </summary>
  133.     public class MonitorSample
  134.     {
  135.         public static void Main(String[] args)
  136.         {
  137.             int result = 0;
  138.             // 一个标志位,如果是0表示程序没有出错,如果是1表明有错误发生
  139.             Cell cell = new Cell();
  140.             // 下面使用cell初始化CellProd和CellCons两个类,生产和消费次数均为20次
  141.             CellProd prod = new CellProd(cell, 20);
  142.             CellCons cons = new CellCons(cell, 20);
  143.             // 生产者线程
  144.             Thread producer = new Thread(new ThreadStart(prod.ThreadRun));
  145.             // 消费者线程
  146.             Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));
  147.             // 生产者线程和消费者线程都已经被创建,但是没有开始执行 
  148.             try
  149.             {
  150.                 producer.Start();
  151.                 consumer.Start();
  152.                 producer.Join();
  153.                 consumer.Join();
  154.                 Console.ReadLine();
  155.             }
  156.             catch (ThreadStateException e)
  157.             {
  158.                 // 当线程因为所处状态的原因而不能执行被请求的操作
  159.                 Console.WriteLine(e);
  160.                 result = 1;
  161.             }
  162.             catch (ThreadInterruptedException e)
  163.             {
  164.                 // 当线程在等待状态的时候中止
  165.                 Console.WriteLine(e);
  166.                 result = 1;
  167.             }
  168.             // 尽管Main()函数没有返回值,但下面这条语句可以向父进程返回执行结果
  169.             // 获取或设置进程的退出代码
  170.             Environment.ExitCode = result;
  171.         }
  172.     }
  173. }