zoukankan      html  css  js  c++  java
  • 211. Orchard学习 二 2、ManualResetEvent 与 AutoResetEvent

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

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

       1: /// <summary>
       2: /// 启动 System.Web.HttpApplication.BeginRequest 的异步处理的 System.Web.BeginEventHandler
       3: /// System.Web.HttpApplication.BeginRequest 在 ASP.NET 响应请求时作为 HTTP 执行管线链中的第一个事件发生。 
       4: /// </summary>
       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: /// <summary>
       2: /// AsyncResult for "on hold" request (resumes when "Completed()" is called)
       3: /// </summary>
       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: /// <summary>
      23: /// 已 “执行完成 or 正在处理” 的异步操作状态
      24: /// Async result for "ok to process now" requests
      25: /// </summary>
      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事件通知处理器。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<ManualResetEvent>(new ManualResetEvent(true));
       9:         //var resetEventHandler = new ResetEventHandle<AutoResetEvent>(new AutoResetEvent(true));
      10:         Common.ConsoleWriteLine(" Type: " + resetEventHandler.CurTypeName, false);
      11:         Common.ConsoleWriteLine(" MainThread: ");
      12:         Common.ConsoleWriteLine("
    ", 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<T> where T : EventWaitHandle
       2: {
       3:     /// <summary>test
       4:     /// 通知一个或多个正在等待的线程已发生事件,处理器类型。      “等待线程 事件通知 处理器”.
       5:     /// ManualResetEvent 继承自 ,EventWaitHandle:WaitHandle , 表示一个线程同步事件。 
       6:     /// EventWaitHandle 主要操作方法: Set() , Reset()。
       7:     /// WaitHandle 封装等待对共享资源的独占访问的操作系统特定的对象
       8:     /// </summary>
       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:     /// <summary>
      23:     /// 将事件状态设置为终止状态, 即目前已无事件发生,无需等待,其他等待中的线程继续运行
      24:     /// </summary>
      25:     public void Set() { this._resetEventHandler.Set(); }
      26:  
      27:     /// <summary>
      28:     /// 将事件状态设置为非终止状态,即目前有事件发生,需等待,其他线程暂停运行
      29:     /// </summary>
      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,创建的三个线程继续运行,但一次只运行一个线程,其他被阻塞的线程则继续等待通知信号:

    image

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

    image

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

    image

    四、一点总结:

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

     

    DEMO代码

    https://bitbucket.org/wsliujun/700-01-consoleapp_resetevent/

    相关参考

    http://www.cnblogs.com/tianzhiliang/archive/2011/03/04/1970726.html

    http://www.cnblogs.com/qingyun163/archive/2013/01/05/2846633.html

    http://msdn.microsoft.com/zh-cn/library/system.threading.manualresetevent.aspx

    http://msdn.microsoft.com/zh-cn/library/system.threading.autoresetevent.aspx

  • 相关阅读:
    中学数学
    XBT Tracker 服务器配置
    【转】>Unity3d动态数据管理(Export AssetBundles)
    [转]MySQL 5.1.56 for Windows XP/Vista/7
    [转]全面理解Unity加载和内存管理
    [转]Unity3D Editor 编辑器简易教程
    Dow falls 97 points, worst showing this year
    [转]Boost库编译后命名方式
    free falling
    01、Direct3D 11 Basics
  • 原文地址:https://www.cnblogs.com/acejason/p/4064838.html
Copyright © 2011-2022 走看看