最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也简要提了一下System.Threading.WaitHandle.WaitOne 、System.Threading.WaitHandle.WaitAny和System.Threading.WaitHandle.WaitAll ,下面我们一最初学者的角度来看,多线程之间的同步。

假设有这样的一个场景,主线程开了一个子线程,让子线程等着,等主线程完成了某件事情时再通知子线程去往下执行,这里关键就在于这个怎让子线程等着,主线程怎通知子线程,一般情况下我们不难想到用一个公共变量,于是咱们就有了下面的代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;namespace AutoResetEventTest
{class Class1{static bool flag = true;static void DoWork(){Console.WriteLine("   worker thread started, now waiting on event...");while (flag){}Console.WriteLine("   worker thread reactivated, now exiting...");}static void Main(){Console.WriteLine("main thread starting worker thread...");Thread t = new Thread(DoWork);t.Start();Console.WriteLine("main thrad sleeping for 1 second...");Thread.Sleep(1000);Console.WriteLine("main thread signaling worker thread...");flag = false;}}
}

虽然目的达到了,但是看着这代码就纠结,下面该是我们的主角上场了,AutoResetEvent 和 ManualResetEvent,关于这两者我们暂且认为是差不多了,稍后我会介绍他们的不同,这里以AutoResetEvent为例,其实很多官方的说法太过于抽象,这里通俗地讲,可以认为AutoResetEvent就是一个公共的变量(尽管它是一个事件),创建的时候可以设置为false,然后在要等待的线程使用它的WaitOne方法,那么线程就一直会处于等待状态,只有这个AutoResetEvent被别的线程使用了Set方法,也就是要发通知的线程使用了它的Set方法,那么等待的线程就会往下执行了,Set就是发信号,WaitOne是等待信号,只有发了信号,等待的才会执行。如果不发的话,WaitOne后面的程序就永远不会执行。好下面看用AutoResetEvent改造上面的程序:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;namespace AutoResetEventTest
{class Class2{static AutoResetEvent mEvent=new AutoResetEvent(false);//static ManualResetEvent mEvent = new ManualResetEvent(false);static void DoWork(){Console.WriteLine("   worker thread started, now waiting on event...");mEvent.WaitOne();Console.WriteLine("   worker thread reactivated, now exiting...");}static void Main(){Console.WriteLine("main thread starting worker thread...");Thread t = new Thread(DoWork);t.Start();Console.WriteLine("main thrad sleeping for 1 second...");Thread.Sleep(1000);Console.WriteLine("main thread signaling worker thread...");mEvent.Set();}}
}

这时代码是不是清爽多了,这里其实你还会看到,把上面的AutoResetEvent换成ManualResetEvent也是没有问题的,那么它两之间的区别是什么呢?个人认为它们最大的区别在于,无论何时,只要 AutoResetEvent 激活线程,它的状态将自动从终止变为非终止。相反,ManualResetEvent 允许它的终止状态激活任意多个线程,只有当它的 Reset 方法被调用时才还原到非终止状态。开下面的代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;namespace AutoResetEventTest
{class Class3{static AutoResetEvent mEvent = new AutoResetEvent(false);//static ManualResetEvent mEvent = new ManualResetEvent(false);static void DoWork(){Console.WriteLine("   worker thread started, now waiting on event...");for (int i = 0; i < 3; i++){mEvent.WaitOne();//mEvent.Reset();Console.WriteLine("   worker thread reactivated, now exiting...");}}static void Main(){Console.WriteLine("main thread starting worker thread...");Thread t = new Thread(DoWork);t.Start();for (int i = 0; i < 3; i++){Thread.Sleep(1000);Console.WriteLine("main thread signaling worker thread...");mEvent.Set();}}}
}

如果你想仅仅把AutoResetEvent换成ManualResetEvent的话,你发现输出就会乱套了,为什么呢?

假如有autoevent.WaitOne()和manualevent.WaitOne(),当线程得到信号后都得以继续执行。差别就在调用后,autoevent.WaitOne()每次只允许一个线程进入,当某个线程得到信号(也就是有其他线程调用了autoevent.Set()方法后)后,autoevent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只有继续等待,也就是说,autoevent一次只唤醒一个线程。而manualevent则可以唤醒多个线程,当某个线程调用了set方法后,其他调用waitone的线程获得信号得以继续执行,而manualevent不会自动将信号置为不发送,也就是说,除非手工调用了manualevent.Reset()方法,否则manualevent将一直保持有信号状态,manualevent也就可以同时唤醒多个线程继续执行。

在上面代码中,如果将AutoResetEvent换成ManualResetEvent的话,只要要在waitone后面做下reset,就会达到同样的效果。

之后咱们再来个简单的例子:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;namespace AutoResetEventTest
{class Class4{public static AutoResetEvent mEvent = new AutoResetEvent(false);public static void trmain(){Thread tr = Thread.CurrentThread;Console.WriteLine("thread: waiting for an event");mEvent.WaitOne();Console.WriteLine("thread: got an event");for (int x = 0; x < 10; x++){Thread.Sleep(1000);Console.WriteLine(tr.Name + ": " + x);}}static void Main(string[] args){Thread thrd1 = new Thread(new ThreadStart(trmain));thrd1.Name = "thread1";thrd1.Start();for (int x = 0; x < 10; x++){Thread.Sleep(900);Console.WriteLine("Main:" + x);if (5 == x) mEvent.Set();}while (thrd1.IsAlive){Thread.Sleep(1000);Console.WriteLine("Main: waiting for thread to stop");}}}
}

是不是更有感觉了?之后咱来看看另外几个东东:

System.Threading.WaitHandle.WaitOne 使线程一直等待,直到单个事件变为终止状态;

System.Threading.WaitHandle.WaitAny 阻止线程,直到一个或多个指示的事件变为终止状态;

System.Threading.WaitHandle.WaitAll 阻止线程,直到所有指示的事件都变为终止状态。

然后再来个例子,以WaitAll使用为例:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;namespace AutoResetEventTest
{class other{static void Main(string[] args){Random randomGenerator = new Random();AutoResetEvent[] resets=new AutoResetEvent[5];for (int i = 0; i < 5; i++){resets[i] = new AutoResetEvent(false);int wTime = randomGenerator.Next(10)+1;worker w = new worker(wTime, resets[i]);Thread thrd1 = new Thread(new ThreadStart(w.work));thrd1.Start();  }WaitHandle.WaitAll(resets);Console.WriteLine("ALL worker done - main exiting.");}}public class worker{public string name;public int wTime;public AutoResetEvent mEvent;public worker(int w, AutoResetEvent m){name = w.ToString();wTime = w * 1000;mEvent = m;}public void work(){Console.WriteLine(name + " worker thread waiting for " + wTime + "....");Thread.Sleep(wTime);Console.WriteLine(name + " worker thread back...");mEvent.Set();}}
}

简单来说就是,开了5个线程,每个线程随机休眠若干秒,都完成后通知主线程退出,这里就开了一个AutoResetEvent数组,主线程就WaitHandle.WaitAll(resets) ,子线程休眠完后就Set1个AutoResetEvent,最后都Set完后,主线程就会往下执行。最后最后再来个买书付款取货的例子,加深理解:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;namespace AutoResetEventTest
{class Program{const int numIterations = 10;static AutoResetEvent myResetEvent = new AutoResetEvent(false);static AutoResetEvent ChangeEvent = new AutoResetEvent(false);//static ManualResetEvent myResetEvent = new ManualResetEvent(false);//static ManualResetEvent ChangeEvent = new ManualResetEvent(false);static int number; //这是关键资源static void Main(){Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));payMoneyThread.Name = "付钱线程";Thread getBookThread = new Thread(new ThreadStart(GetBookProc));getBookThread.Name = "取书线程";payMoneyThread.Start();getBookThread.Start();for (int i = 1; i <= numIterations; i++){Console.WriteLine("买书线程:数量{0}", i);number = i;//Signal that a value has been written.myResetEvent.Set();//ChangeEvent.Set();Thread.Sleep(10);}payMoneyThread.Abort();getBookThread.Abort();}static void PayMoneyProc(){while (true){myResetEvent.WaitOne();//myResetEvent.Reset();Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);ChangeEvent.Set();}}static void GetBookProc(){while (true){ChangeEvent.WaitOne();//ChangeEvent.Reset();               Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);Console.WriteLine("------------------------------------------");//Thread.Sleep(0);}}}
}

本文部分资料来源于网络,特此声明!

相关链接:http://www.cnblogs.com/freshman0216/archive/2008/07/30/1252345.html

http://msdn.microsoft.com/zh-cn/library/z6w25xa6%28VS.80%29.aspx

C#多线程同步事件及等待句柄相关推荐

  1. 多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)

    多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上) 转自 http://www.cnblogs.com/freshman0216/archive/2008/07/27/ ...

  2. [Java][Android] 多线程同步-主线程等待全部子线程完毕案例

    有时候我们会遇到这种问题:做一个大的事情能够被分解为做一系列相似的小的事情,而小的事情无非就是參数上有可能不同样而已! 此时,假设不使用线程,我们势必会浪费许多的时间来完毕整个大的事情.而使用线程的话 ...

  3. 多线程编程(14) - 多线程同步之 WaitableTimer (等待定时器对象)

    function CreateWaitableTimer(lpTimerAttributes: PSecurityAttributes; {安全}bManualReset: BOOL; {True: ...

  4. 多线程同步之 WaitableTimer (等待定时器对象)[续三]

    根据 WaitableTimer 的主要功用, 现在再把它放在 "线程同步" 的话题中讨论有点不合适了, 就要结束它. TimerAPCProc(lpArgToCompletion ...

  5. 多线程编程(15) - 多线程同步之 WaitableTimer (等待定时器对象)[续]

    本次专门研究下 SetWaitableTimer 的第二个参数(起始时间). 它有正值.负值.0值三种情况, 前面已用过 0值. 先学习负值(相对时间), 也就是从当前算起隔多长时间开始执行. 这个相 ...

  6. C++实现多线程及其三种方法实现多线程同步

    1.调用windows API实现多线程 #include "stdafx.h" #include <windows.h> #include <stdio.h&g ...

  7. python 同步 事件 event 简介

    目录 1. Event 1.1 set() 1.2 wait() 1.3 clear() 1.4 is_set() 2. 协调线程同步 3. 一个更复杂的例子 事件 Event是另一种python多线 ...

  8. 秒杀多线程第六篇 经典线程同步 事件Event

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题 ...

  9. Windows多线程(四) 经典线程同步 事件Event

    第一个 CreateEvent 函数功能:创建事件 函数原型: HANDLECreateEvent( LPSECURITY_ATTRIBUTESlpEventAttributes, BOOLbManu ...

最新文章

  1. Spring微服务视频免费发放
  2. 代写SOFTENG 370 Operating Systems课设、代做C/C++ 留学生作业、代写c/c++代码、代写C/C++编程作业...
  3. 电脑没有ps怎么改照片dpi_PS入门的小技巧来啦!小白们还在等什么呢?快进来啊!...
  4. 如果谁和飞鸽传书讨论这两个问题
  5. 网络协议:TCP连接管理
  6. 学习ssm框架一般要用多少时间
  7. Web前端JavaScript笔记(7)ECMA6新增数组方法
  8. php评论倒序 zblog_zblogPHP评论链接加密并美化跳转的完美方法
  9. Java将excel文件转成json文件(有错误)
  10. 每日一句20200119
  11. 讯飞输入法第11次作答:效率升维、场景细分、个性满足
  12. PreScan Regenerate问题
  13. McAfee (麦咖啡) 360安全卫士 金山毒霸2008正式免费升级版 超级巡警 IceSword(冰刃)
  14. 北航计算机专业报录比,北京航空航天大学考研报录比数据查询
  15. sql中between and 用法
  16. minIO安装教程及代码使用
  17. IEEE 软件单元测试标准
  18. 基本粒子结构以及宇宙现象的徦说
  19. 引用pdf插件在线预览的问题
  20. java展示树形结构的两种方式

热门文章

  1. IoT黑板报:苹果瑞士建秘密实验室开发自动驾驶
  2. 根据用户ID查询上级和上上级组织机构
  3. laravel清理缓存(config:clear)后导致程序崩溃
  4. Android shape画虚线,不显示或者显示是实线的解决方案
  5. 结构体变量内存申请与释放
  6. 全栈工程师到底有什么用?
  7. 网络安全应急响应具体操作流程
  8. 可控文本生成系列-A Survey of Controllable Text Generation using Transformer-based Pre-trained
  9. uniapp小程序消息订阅功能
  10. 穿越派私有云盘全网永不关机设置方法