博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
211. Orchard学习 二 2、ManualResetEvent 与 AutoResetEvent
阅读量:5077 次
发布时间:2019-06-12

本文共 7830 字,大约阅读时间需要 26 分钟。

一、Orchard里异步请求处理线程队列的控制

Orchard的Orchard.WarmupStarter模块,为HttpApplication.BeginRequest时间附加了一个异步处理事件:BeginBeginRequest。

1: /// 
2: /// 启动 System.Web.HttpApplication.BeginRequest 的异步处理的 System.Web.BeginEventHandler
3: /// System.Web.HttpApplication.BeginRequest 在 ASP.NET 响应请求时作为 HTTP 执行管线链中的第一个事件发生。
4: /// 
5: private IAsyncResult BeginBeginRequest(object sender, EventArgs e, AsyncCallback cb, object extradata)
6: {
7:     // host is available, process every requests, or file is processed
8:     if (!InWarmup() || WarmupUtility.DoBeginRequest(_context))
9:     {
10:         /***
11:          *  !InWarmup()  不在预热中
12:          *  WarmupUtility.DoBeginRequest(_context) 找到了与请求URL匹配的静态文件资源
13:          */
14:         var asyncResult = new DoneAsyncResult(extradata);
15:         cb(asyncResult);
16:         return asyncResult;
17:     }
18:     else
19:     {
20:         // this is the "on hold" execution path
21:         var asyncResult = new WarmupAsyncResult(cb, extradata);
22:         Await(asyncResult.Completed);
23:         return asyncResult;
24:     }
25: }

在请求开始时,检查系统状态,“不在预热中”或者找到了与请求的URL匹配的静态文件资源,则构造一个 DoneAsncResult类型实例,执行并返回结果状态。如果正在预热,或没有匹配的静态文件资源,将请求加入一个待执行队列,直到预热完成发出信号后再执行(这个见Orchard.WarmupStarter.Starter.LaunchStartupThread())。

我们再来看 DoneAsyncResult和WarmupAsyncResult

1: /// 
2: /// AsyncResult for "on hold" request (resumes when "Completed()" is called)
3: /// 
4: private class WarmupAsyncResult : IAsyncResult
5: {
6:     /****************
7:     // 通知一个或多个正在等待的线程已发生事件,处理器类型。      “等待线程 事件通知 处理器”.
8:     // AutoResetEvent 继承自 ,EventWaitHandle:WaitHandle , 表示一个线程同步事件。
9:     // EventWaitHandle 主要操作方法: Set() , Reset()。
10:     // WaitHandle 封装等待对共享资源的独占访问的操作系统特定的对象
11:
12:     // 初始化一个  “等待线程 事件通知 处理器” 。
13:     // 参数 initialState ,初始状态是否为 终止:
14:     //     true   终止  ,即目前已无事件发生,无需等待,线程继续运行
15:     //     false  非终止,即目前有事件发生,需等待,线程暂停运行
16:     ****************/
17:     private readonly EventWaitHandle _eventWaitHandle = new AutoResetEvent(false/*initialState*/);
18: 
19:     //...省略若干代码
20: }
21: 
22: /// 
23: /// 已 “执行完成 or 正在处理” 的异步操作状态
24: /// Async result for "ok to process now" requests
25: /// 
26: private class DoneAsyncResult : IAsyncResult
27: {
28:     /****************
29:     // 通知一个或多个正在等待的线程已发生事件,处理器类型。      “等待线程 事件通知 处理器”.
30:     // ManualResetEvent 继承自 ,EventWaitHandle:WaitHandle , 表示一个线程同步事件。
31:     // EventWaitHandle 主要操作方法: Set() , Reset()。
32:     // WaitHandle 封装等待对共享资源的独占访问的操作系统特定的对象
33:
34:     // 初始化一个  “等待线程 事件通知 处理器” 。
35:     // 参数 initialState ,初始状态是否为 终止:
36:     //     true   终止  ,即目前已无事件发生,无需等待,线程继续运行
37:     //     false  非终止,即目前有事件发生,需等待,线程暂停运行
38:     ****************/
39:     private static readonly WaitHandle _waitHandle = new ManualResetEvent(true/*initialState*/);
40: 
41:     //...省略若干代码
42: }

他们分别实例化了事件通知处理器。AutoResetEvent 和 ManualResetEvent 都继承自 EventWaitHandle,WaitHandle ,表示一个线程同步事件通知器。 通俗的讲,就是程序中需要跨多个线程处理协调事件时,一个用来通知协调事件处理状态的处理器。

EventWaitHandle 主要操作方法:

  • Set() :将事件状态设置为终止状态,即目前已无事件发生,无需等待,其他等待中的线程继续运行;
  • Reset() :将事件状态设置为非终止状态,即目前有事件发生,需等待,其他线程暂停运行;
  • WaitOne():阻塞当前线程 ,直到 _resetEventHandler 收到新的事件信号(即 set or reset);

AutoResetEvent 和 ManualResetEvent初始化时,参数 initialState ,初始状态是否为 终止。其表意如下:

  • true 终止 ,即目前已无事件发生,无需等待,线程继续运行,
  • false 非终止,即目前有事件发生,需等待,线程暂停运行

 

二、AutoResetEvent 与 ManualResetEvent

看起来 AutoResetEvent 和 ManualResetEvent 很像,我们通过一个demo来看看他们的区别

Class Program 与 CLaunchStartupThread

1: class Program
2: {
3:     static void Main(string[] args)
4:     {
5:         Common.ConsoleWriteLine("----------------------", false);
6:         Common.ConsoleWriteLine(" S 暂停      R 继续   ", false);
7: 
8:         var resetEventHandler = new ResetEventHandle
(new ManualResetEvent(true));
9:         //var resetEventHandler = new ResetEventHandle
(new AutoResetEvent(true));
10:         Common.ConsoleWriteLine(" Type: " + resetEventHandler.CurTypeName, false);
11:         Common.ConsoleWriteLine(" MainThread: ");
12:         Common.ConsoleWriteLine("\r\n", false);
13:         //创建线程
14:         Common.CreateThreads(resetEventHandler.Run, 3);
15: 
16:         while (true)
17:         {
18:             string input = Console.ReadLine();
19:             if (input.Trim().ToLower() == "s")
20:             {
21:                 Common.ConsoleWriteLine("线程 暂停 运行.");
22:                 resetEventHandler.Reset();
23:             }
24:             else if (input.Trim().ToLower() == "r")
25:             {
26:                 Common.ConsoleWriteLine("线程 继续 运行.");
27:                 resetEventHandler.Set();
28:             }
29:         }
30: 
31:     }
32: }
33: class Common
34: {
35:     public static void CreateThreads(Action runFunc, int tCount = 2)
36:     {
37:         var i = 0;
38:         while (i < tCount)
39:         {
40:             var t = new Thread(new ThreadStart(runFunc));
41:             t.Start();
42:             i++;
43:         }
44:     }
45:     public static void ConsoleWriteLine(string msg, bool withThreadSign = true, bool withDateTimeSign = false)
46:     {
47:         Console.WriteLine(
48:             msg +
49:             (withThreadSign ? (" [ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString() + " ]") : "") +
50:             (withDateTimeSign ? ("[" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "]") : "")
51:             );
52:     }
53: }
ResetEventHandle.cs
1: class ResetEventHandle
where T : EventWaitHandle
2: {
3:     /// test
4:     /// 通知一个或多个正在等待的线程已发生事件,处理器类型。      “等待线程 事件通知 处理器”.
5:     /// ManualResetEvent 继承自 ,EventWaitHandle:WaitHandle , 表示一个线程同步事件。
6:     /// EventWaitHandle 主要操作方法: Set() , Reset()。
7:     /// WaitHandle 封装等待对共享资源的独占访问的操作系统特定的对象
8:     /// 
9:     private T _resetEventHandler;
10: 
11:     public ResetEventHandle(T resetEventHandler)
12:     {
13:         // 初始化一个  “等待线程 事件通知 处理器” 。
14:         // 参数 initialState ,初始状态是否为 终止:
15:         //     true   终止  ,即目前已无事件发生,无需等待程暂,线程继续运行
16:         //     false  非终止,即目前有事件发生,需等待,线停运行
17:         // this._mre = new ManualResetEvent(true);
18:         this._resetEventHandler = resetEventHandler;
19:     }
20: 
21:     public string CurTypeName { get { return _resetEventHandler.GetType().Name; } }
22:     /// 
23:     /// 将事件状态设置为终止状态, 即目前已无事件发生,无需等待,其他等待中的线程继续运行
24:     /// 
25:     public void Set() { this._resetEventHandler.Set(); }
26: 
27:     /// 
28:     /// 将事件状态设置为非终止状态,即目前有事件发生,需等待,其他线程暂停运行
29:     /// 
30:     public void Reset() { this._resetEventHandler.Reset(); }
31: 
32:     public void Run()
33:     {
34:         string strThreadID = string.Empty;
35:         try
36:         {
37:             while (true)
38:             {
39:                 // 阻塞当前线程 ,直到 _resetEventHandler 收到新的事件信号(即 set or reset)
40:                 this._resetEventHandler.WaitOne();
41: 
42:                 strThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
43:                 Common.ConsoleWriteLine("线程 (" + strThreadID + ") 正在运行.");
44: 
45:                 Thread.Sleep(5000);
46:             }
47:         }
48:         catch (Exception ex)
49:         {
50:             Common.ConsoleWriteLine("线程 (" + strThreadID + ") 异常!错误:" + ex.Message.ToString());
51:         }
52:     }
53: }
在Program.Main()中,如果调用AutoResetEvent类型,我们每次输入r,创建的三个线程继续运行,但一次只运行一个线程,其他被阻塞的线程则继续等待通知信号:

如果调用ManualResetEvent类型,我们每次输入r,创建的三个线程继续运行,每次所有创建后被阻塞的线程都会运行起来:

三、生活中的例子:

参考文档中,所列公路收费站的例子并不恰当。我们参考一下地铁闸机:

 

四、一点总结:

    • ManualResetEvent 和 AutoResetEvent都可以继续运行或阻塞线程,并且都是一次性阻塞所有影响到的线程;
    • ManualResetEvent 是一次继续运行一批线程;
    • AutoResetEvent 是一次继续运行一个线程,其他影响到的线程继续等待新的事件通知信号;
    • AutoResetEvent.Set() = ManualResetEvent.Set() + ManualResetEvent.Reset();
    • 如果共享资源仅允许单线程使用的情况下,应选择AutoResetEvent;如果共享资源允许多个线程同时使用,则可以选择ManualResetEvent;
    • 言外之意,只有一个待处理线程时,ManualResetEvent 和 AutoResetEvent效果是一致的。

 

DEMO代码

相关参考

转载于:https://www.cnblogs.com/acejason/p/4064838.html

你可能感兴趣的文章
硬件笔记之Thinkpad T470P更换2K屏幕
查看>>
蓝桥杯-分小组-java
查看>>
Android Toast
查看>>
JAVA面试常见问题之Redis篇
查看>>
jdk1.8 api 下载
查看>>
getElement的几中属性介绍
查看>>
HTML列表,表格与媒体元素
查看>>
Introduction to my galaxy engine 2: Depth of field
查看>>
设计器 和后台代码的转换 快捷键
查看>>
STL容器之vector
查看>>
数据中心虚拟化技术
查看>>
复习文件操作
查看>>
SQL Server 使用作业设置定时任务之一(转载)
查看>>
第二阶段冲刺-01
查看>>
BZOJ1045 HAOI2008 糖果传递
查看>>
JavaScript 克隆数组
查看>>
eggs
查看>>
oracle 报错ORA-12514: TNS:listener does not currently know of service requested in connec
查看>>
基于grunt构建的前端集成开发环境
查看>>
利用循环播放dataurl的视频来防止锁屏:NoSleep.js
查看>>