码迷,mamicode.com
首页 > 编程语言 > 详细

c#多线程之EventWaitHandle再次使用

时间:2017-05-18 20:03:22      阅读:380      评论:0      收藏:0      [点我收藏+]

标签:根据   bool   turn   model   取消   task   理解   ext   class   

 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放到队列里,紧接着,通过autoResetEvent.Set()方法,释放被阻塞的线程。此时如果有三个线程,队列里只有1个model,那么三个线程消费一个model,必然有两个线程直接被阻塞了,那个得到model的线程执行完毕后,也被阻塞了,一直到下一个model进队,这三个线程就像三名运动员跑着去搬东西,如果东西搬完了,就原地待命,听枪响,那什么时候枪响呢?如果有东西来了,那么就会开枪。于是三名运动员竭尽全力去抢东西,如果其中有一人抢到了,那么其它两人就原地待命,如果要搬运的东西比较多的话,那么这三名运动员就一直忙碌,按照先来先搬的原则,搬了就走。

      按照刚才的理解,那么AutoResetEvent,就是刚才那把枪,它有两种状态,一种是开枪状态(非终止状态) ,另一种是已经开过枪状态(终止状态)。如果已经开过枪了,那么什么时候状态会变化呢?我觉得应该是开枪后,autoResetEvent.WaitOne()阻塞的线程继续运行,然后状态自动变为开枪状态,以便下一次再开枪。WaitOne就是等待枪声,否则一直阻塞。如果此时有多个线程都在阻塞,听到枪声后,只有一个线程被释放。这点很关键,否则在设计多线程的程序时,会有意想不到的结果。

 

c#多线程之EventWaitHandle再次使用

标签:根据   bool   turn   model   取消   task   理解   ext   class   

原文地址:http://www.cnblogs.com/wangqiang3311/p/6874975.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!