zoukankan      html  css  js  c++  java
  • c#多线程同步之EventWaitHandle再次使用

     1     /// <summary>
     2     /// 文件传输器,用来获取全文文件,自动根据全文文件数量,开启一定数量的线程,采用生产者消费模式
     3     /// </summary>
     4     public class FileTranser
     5     {
     6         private static IFileTranser Transer = new RealFileTranser();
     7         // 文件队列
     8         static Queue<FullTextListViewModel> FileTaskQueue = new Queue<FullTextListViewModel>();
     9         // 为保证线程安全,使用一个锁来保护队列的访问
    10         readonly static object locker = new object();
    11         // 通过 autoResetEvent 给工作线程发信号
    12         static EventWaitHandle autoResetEvent = new AutoResetEvent(false);
    13         public static CancellationTokenSource cancel = null;
    14 
    15         static int MaxThreadCount = 5;
    16         static int MinThreadCount = 1;
    17         static int PageSize = 100;
    18 
    19         static List<Thread> threads = new List<Thread>();
    20         static bool IsRunning = false;
    21         public static void Start(FullTextListViewModel model, int total)
    22         {
    23             if (cancel != null && cancel.IsCancellationRequested) return;
    24             if (IsRunning == false || threadCount > threads.Count)
    25             {
    26                 int startCount = threadCount - threads.Count;
    27                 IsRunning = true;
    28                 // 任务开始,启动工作线程
    29                 for (int i = 0; i < startCount; i++)
    30                 {
    31                     Thread t = new Thread(Work);
    32                     t.Name = "f_" + (i + 1);
    33                     t.IsBackground = false;
    34                     t.Start();
    35                     threads.Add(t);
    36                 }
    37             }
    38             lock (locker)
    39             {
    40                 FileTaskQueue.Enqueue(model);
    41             }
    42             autoResetEvent.Set();
    43         }
    44         public static void Cancel()
    45         {
    46             IsRunning = false;
    47             threads.Clear();
    48             if (cancel != null)
    49             {
    50                 cancel.Cancel();
    51             }
    52             autoResetEvent.Set();
    53             Logger.Log("取消获取全文的线程执行");
    54         }
    55         /// <summary>执行工作</summary>
    56         static void Work()
    57         {
    58             while (true)
    59             {
    60                 if (cancel.IsCancellationRequested)
    61                 {
    62                     Logger.Log("线程已取消,当前线程:" + Thread.CurrentThread.Name);
    63                     autoResetEvent.Set();
    64                     break;
    65                 }
    66                 else
    67                 {
    68                     FullTextListViewModel model = null;
    69                     lock (locker)
    70                     {
    71                         if (FileTaskQueue.Count > 0)
    72                         {
    73                             model = FileTaskQueue.Dequeue();
    74                         }
    75                     }
    76                     if (model != null)
    77                     {
    78                         Logger.Log("全文传输文件已经开始,当前Id:" + model.ClientTaskId + ",当前线程:" + Thread.CurrentThread.Name);
    79                         FileTranser.Transer.DoWork(model);
    80                     }
    81                     else
    82                     {
    83                         Logger.Log("线程" + Thread.CurrentThread.Name + ",已被阻塞,等待任务");
    84                         autoResetEvent.WaitOne();
    85                     }
    86                 }
    87             }
    88         }
    89     }

         这段不到100行的代码,采用的思想是,生产者消费模式,其中应用了AutoResetEvent ,从字面上看,是自动重置事件,它是EventWaitHandle的一个子类。

         我们还是先来看看这段代码所要表达的意思。第8行,定义了一个文件传输队列FileTaskQueue,它用来接收生产者生产的实体,即FullTextListViewModel类型的对象。29-35行,开启了若干个线程,40行,给队列加锁,把model放到队列里,紧接着,通过Set方法,释放被阻塞的线程。此时,如果有三个线程,队列里只有1个model,那么三个线程消费一个model,必然有两个线程直接被阻塞了,那个得到model的线程执行完毕后,也被阻塞了,一直到下一个model进队,再次运行Set方法, 它们当中只有一个线程被解除了阻塞,接着干活,其它线程的继续等待。如果有足够多的model进队了,意味着活多了,这三个线程都会忙碌起来,不会阻塞。

         autoResetEvent,每次调用set方法时,只有一个线程被释放。这点很关键,否则在设计多线程的程序时,会有意想不到的结果。

  • 相关阅读:
    C++中break语句、continue语句和goto语句区别
    面试题 01.03:URL化(C++)
    面试题 01.02: 判定是否互为字符重排(C++)
    面试题 01.01: 判定字符是否唯一(C++)
    探索one
    面试题32
    面试题32
    面试题32
    面试题33: 二叉搜索树的后序遍历序列(C++)
    用命令行执行php脚本输出乱码
  • 原文地址:https://www.cnblogs.com/wangqiang3311/p/6874975.html
Copyright © 2011-2022 走看看