Autosetevent reseteventt.WaitOne(1000,true) 退出同步域是什么意思?

ManualResetEvent和AutoResetEvent的区别
在讨论这个问题之前,我们先了解这样一种观点,线程之间的通信是通过发信号来进行沟通的。(这不是废话)
&&&&& 先来讨论ManualResetEvent,讨论过程中我会穿插一些AutoResetEvent的内容,来做对比:
&&&&&&ManualResetEvent都可以阻塞一个或多个线程,直到收到一个信号告诉ManualResetEvent不要再阻塞当前的线程。
可以想象ManualResetEvent这个对象内部有一个Boolean类型的属性IsRelease来控制是否要阻塞当前线程。这个属性我们在初始化的时候可以设置它,如ManualResetEvent event=new ManualResetEvent(false);这就表明默认的属性是要阻塞当前线程。
&&&&& 代码举例:
&&&&&&& ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
&&&&&&& private void BT_Temp_Click(object sender, RoutedEventArgs e)
&&&&&&&&&&& Thread t1 = new Thread(this.Thread1Foo);
&&&&&&&&&&& t1.Start();&//启动线程1
&&&&&&&&&&& Thread t2 = new Thread(this.Thread2Foo);
&&&&&&&&&&& t2.Start();&//启动线程2
&&&&&&&&&&& Thread.Sleep(3000);&//睡眠当前主线程,即调用BT_Temp_Click的线程
&&&&&&&&&&& _manualResetEvent .Set();&& //想象成将IsRelease设为True&
&&&&&&& void Thread1Foo()
&&&&&&&&&&& _manualResetEvent .WaitOne();&
//阻塞线程1,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,
//这时不再阻塞线程1,程序继续往下跑
&&&&&&&&&&& MessageBox.Show(&t1 end&);
&&&&&&& void Thread2Foo()
&&&&&&&&&&& _manualResetEvent .WaitOne();
//阻塞线程2,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,
//这时不再阻塞线程2,程序继续往下跑
&&&&&&&&&&& MessageBox.Show(&t2 end&);
&&&&&& 注意这里ManualResetEvent和AutoResetEvent的一个重要区别:
&&&&&& manual的话肯定会给线程1和线程2都发送一个信号,而auto只会随机给其中一个发送信号。
&&&&&& 为什么一个叫manual而一个叫auto呢?我想这是很多人的疑问,现在我们就来看这个问题。
&&&&&& 刚才_manualResetEvent .Set();的这句话我想大家都明白了,可以看做将IsRelease的属性设置为true.线程1中
&_manualResetEvent.WaitOne();接收到信号后不再阻塞线程1。在此之后的整个过程中IsRelease的值都是true.如果
想将IsRelease的值回复成false,就必须再调用_manualResetEvent.Reset()的方法。
&&&&&& 如果是_autoResetEvent.set(),那么_autoResetEvent.WaitOne()后会自动将IsRelease的值自动设置为false.
这就是为什么一个叫auto,一个叫manual.&&&&Posts - 252,
Articles - 0,
Comments - 597
12:00 by DanielWise, ... 阅读,
第三种同步策略关注手动同步技术,.NET Framework 提供了一个经典的技术套件。他们给了程序员使用类似WIN32线程API的底层线程API来创建和管理多线程应用程序的能力。
下面的表显示了System.Threading 命名空间中可以用于手动同步的一些类。
ManualResetEvent 类
一个ManualResetEvent对象仅能处理signaled(true)或者non-signaled(false)两个状态。ManualResetEvent类继承自WaitHandle类,ManualResetEvent的构造函数接收一个参数用来定义对象的初始值。Set()和Reset()方法返回一个布尔值来指示已经发生的改变是否成功。
下面的代码NETThreadEvent.cs, 显示了使用non-signaled状态的ManualResetEvent类。首先我们创建一个名为mansig 的对象并赋值为false. WaitOne()方法将会等待mansig返回true或者时间超时。由于在等待的时间周期里,mansig的值没有被置成true, 所以它停止阻塞并返回false:
/*************************************
/* Copyright (c) 2012 Daniel Dong
* Author:oDaniel Dong
/danielWise
* Email:o
using System.Collections.G
using System.T
using System.T
namespace NETThreadEvents
public class NonSignaledManual
public static void Main()
ManualResetEvent
mansig = new ManualResetEvent(false);
Console.WriteLine("ManualResetEvent Before WaitOne ");
bool b = mansig.WaitOne(1000, false);
Console.WriteLine("ManualResetEvent After WaitOne " + b);
Console.ReadLine();
NETThreadEvents 的执行结果如下:
在NETThreadEvents.cs中,我们构造了一个ManualResetEvent对象(构造函数传值false). 布尔值false将ManualResetEvent对象的初始状态设置为non-signaled. 然后我们调用WaitHandle基类的WaitOne()方法。WaitOne()方法接受两个参数。第一个参数是我们想让线程在WaitOne()方法处等待的时间(毫秒);由于我们将第一个参数设置为1000,所以线程在退出前等待1秒。第二个参数是exitContext. 如果你已经在上下文的同步域中且想退出同步上下文或者你想获得同步上下文,你应该设置这个参数为true.
程序在WaitOne()方法处阻塞1秒然后由于超时退出。ManualResetEvent的状态仍然是false, 因此WaitOne()函数返回false.现在我们要看一下如果我们把ManualResetEvent设置为signaled(true)会发生什么:
/*************************************
/* Copyright (c) 2012 Daniel Dong
* Author:oDaniel Dong
/danielWise
* Email:o
using System.Collections.G
using System.T
using System.T
namespace NETThreadEvents
public class NonSignaledManual
public static void Main()
ManualResetEvent
mansig = new ManualResetEvent(true);
Console.WriteLine("ManualResetEvent Before WaitOne ");
bool b = mansig.WaitOne(1000, false);
Console.WriteLine("ManualResetEvent After WaitOne " + b);
Console.ReadLine();
输出结果如下:
通过将ManualResetEvent的初始状态设置为signaled, 线程不会在WaitOne()方法等待即便我们设定了1000毫秒的超时时间。在之前的例子中ManualResetEvent是non-signaled, 线程等待这个状态变成signaled, 但是在1000毫秒之后它超时了。在现在的这个例子中ManualResetEvent状态已经是non-signaled, 所以没有理由继续在WaitOne()方法上等待。为了将ManualResetEvent的状态改成non-signaled, 我们得调用ManualResetEvent的Reset()方法;如果我们想把ManualResetEvent的状态改成signaled,我们得调用Set()方法。
下面列表ManualReset.cs, 显示了使用Reset()方法;另外一个ManualSet.cs 则显示了Set()方法的使用方法:
/*************************************
/* Copyright (c) 2012 Daniel Dong
* Author:oDaniel Dong
/danielWise
* Email:o
using System.Collections.G
using System.T
using System.T
namespace ManualReset
class Reset
[STAThread]
static void Main()
ManualResetEvent manRE;
manRE = new ManualResetEvent(true);
bool state = manRE.WaitOne(1000, true);
Console.WriteLine("ManualResetEvent After first WaitOne " + state);
//Change the state to non-signaled
manRE.Reset();
state = manRE.WaitOne(5000, true);
Console.WriteLine("ManualResetEvent After second WaitOne " + state);
Console.ReadLine();
ManualReset 的输出结果如下:
在ManualReset中,我们将在ManualResetEvent对象的构造函数中将其状态设置为signaled(true). 所以线程不会在第一个WaitOne()方法处等待并返回true. 然后我们将ManualResetEvent对象的状态重置为non-signaled(false), 所以我们看到线程不得不在超时退出之前等待5秒钟。
在ManualSet.cs 中我们使用Set() 方法:
/*************************************
/* Copyright (c) 2012 Daniel Dong
* Author:oDaniel Dong
/danielWise
* Email:o
using System.Collections.G
using System.T
using System.T
namespace ManualSet
[STAThread]
static void Main(string[] args)
ManualResetEvent manRE;
manRE = new ManualResetEvent(false);
Console.WriteLine("Before WaitOne");
bool state = manRE.WaitOne(5000, true);
Console.WriteLine("ManualResetEvent After first WaitOne " + state);
//Change the state to signaled
manRE.Set();
state = manRE.WaitOne(5000, true);
Console.WriteLine("ManualResetEvent After second WaitOne " + state);
Console.ReadLine();
ManualSet的输出结果如下:
在Manual Set 中,我们将ManualResetEvent对象的初始状态设置为non-signaled(false). 所以线程不得不在第一个WaitOne()方法处等待。然后我们使用Set()方法将这个状态设置为Signaled, 线程拒绝在第二个WaitOne()方法处等待然后退出。
就像WaitOne()方法会等待一个单一事件对象变成signaled一样,WaitAll()方法等待所有的事件对象变成true或者是signaled状态,或者它将等待直到发生超时,而WaitAny()方法则等待任意一个时间对象变成true或者是signaled状态。
下一篇介绍AutoResetEvent, Mutex 以及Interlocked&AutoResetEvent 允许线程通过发信号互相通信。 通常,当线程需要独占访问资源时使用该类。
线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。 如果 AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set 来通知资源可用。
调用 Set 向 AutoResetEvent 发信号以释放等待线程。 AutoResetEvent 将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。 如果没有任何线程在等待,则状态将无限期地保持为终止状态。
如果当 AutoResetEvent 为终止状态时线程调用 WaitOne,则线程不会被阻止。 AutoResetEvent 将立即释放线程并返回到非终止状态。
ManualResetEvent 允许线程通过发信号互相通信。 通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。
当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。 此线程可被视为控制 ManualResetEvent。 调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。 当控制线程完成活动时,它调用Set 以发出等待线程可以继续进行的信号。 并释放所有等待线程。
一旦它被终止,ManualResetEvent 将保持终止状态,直到它被手动重置。 即对 WaitOne 的调用将立即返回。
可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。
ManualResetEvent 也可以同 staticWaitAll 和 WaitAny 方法一起使用。
生活中的例子
AutoResetEvent :在上海坐地铁,检票口有个刷卡的通道,一次只能一个人刷卡后通过,而我过后,它又是关闭的,另一个人又得再刷卡.一次操作,只有一个事件,这时就是非终止状态,一般是用来同步访问资源.
ManualResetEvent :公司园区的大门很大,一次可以多人通过。
ManualResetEvent和AutoResetEvent 比较
ManualResetEvent和AutoResetEvent都继承自EventWaitHandler,它们的唯一区别就在于父类 EventWaitHandler的构造函数参数EventResetMode不同,这样我们只要弄清了参数EventResetMode值不同时,EventWaitHandler类控制线程同步的行为有什么不同,两个子类也就清楚了。
共同点: A、Set方法将事件状态设置为终止状态,允许一个或多个等待线程继续;Reset方法将事件状态设置为非终止状态,导致线程阻止;WaitOne阻止当前线程,直到当前线程的WaitHandler收到事件信号。 B、可以通过构造函数的参数值来决定其初始状态,若为true则事件为终止状态从而使线程为非阻塞状态,为false则线程为阻塞状态。 C、如果某个线程调用WaitOne方法,则当事件状态为终止状态时,该线程会得到信号,继续向下执行。
不同点: A、AutoResetEvent.WaitOne()每次只允许一个线程进入,当某个线程得到信号后,AutoResetEvent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只有继续等待,也就是说AutoResetEvent一次只唤醒一个线程; B、ManualResetEvent则可以唤醒多个线程,因为当某个线程调用了ManualResetEvent.Set()方法后,其他调用WaitOne的线程获得信号得以继续执行,而ManualResetEvent不会自动将信号置为不发送。
C、也就是说,除非手工调用了ManualResetEvent.Reset()方法,则ManualResetEvent将一直保持有信号状态,ManualResetEvent也就可以同时唤醒多个线程继续执行。
先看下AutoResetEvent 的代码
namespace System.Threading {
using System.Security.P
using System.Runtime.InteropS
[HostProtection(Synchronization=true, ExternalThreading=true)]
[System.Visible(true)]
public sealed class AutoResetEvent : EventWaitHandle
public AutoResetEvent(bool initialState) : base(initialState,EventResetMode.AutoReset){ }
再来看下EventWaitHandle的代码
namespace System.Threading
using System.T
using pilerS
using System.Security.P
using System.IO;
using Microsoft.Win32;
using Microsoft.Win32.SafeH
using System.Runtime.InteropS
using System.Runtime.V
#if !FEATURE_PAL
using System.Security.AccessC
[HostProtection(Synchronization=true, ExternalThreading=true)]
[ComVisibleAttribute(true)]
public class EventWaitHandle : WaitHandle
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
public EventWaitHandle(bool initialState, EventResetMode mode) : this(initialState,mode,null) { }
[SecurityPermissionAttribute(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public EventWaitHandle(bool initialState, EventResetMode mode, string name)
if(null != name && System.IO.Path.MAX_PATH & name.Length)
throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong",name));
SafeWaitHandle _handle =
switch(mode)
case EventResetMode.ManualReset:
_handle = Win32Native.CreateEvent(null, true, initialState, name);
case EventResetMode.AutoReset:
_handle = Win32Native.CreateEvent(null, false, initialState, name);
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag",name));
if (_handle.IsInvalid)
int errorCode = Marshal.GetLastWin32Error();
_handle.SetHandleAsInvalid();
if(null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle",name));
__Error.WinIOError(errorCode, "");
SetHandleInternal(_handle);
[SecurityPermissionAttribute(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public EventWaitHandle(bool initialState, EventResetMode mode, string name, out bool createdNew)
#if !FEATURE_PAL
: this(initialState, mode, name, out createdNew, null)
[SecurityPermissionAttribute(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public unsafe EventWaitHandle(bool initialState, EventResetMode mode, string name, out bool createdNew, EventWaitHandleSecurity eventSecurity)
if(null != name && System.IO.Path.MAX_PATH & name.Length)
throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong",name));
Win32Native.SECURITY_ATTRIBUTES secAttrs =
#if !FEATURE_PAL
// For ACL's, get the security descriptor from the EventWaitHandleSecurity.
if (eventSecurity != null) {
secAttrs = new Win32Native.SECURITY_ATTRIBUTES();
secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
byte[] sd = eventSecurity.GetSecurityDescriptorBinaryForm();
byte* pSecDescriptor = stackalloc byte[sd.Length];
Buffer.memcpy(sd, 0, pSecDescriptor, 0, sd.Length);
secAttrs.pSecurityDescriptor = pSecD
SafeWaitHandle _handle =
Boolean isManualR
switch(mode)
case EventResetMode.ManualReset:
isManualReset =
case EventResetMode.AutoReset:
isManualReset =
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag",name));
_handle = Win32Native.CreateEvent(secAttrs, isManualReset, initialState, name);
int errorCode = Marshal.GetLastWin32Error();
if (_handle.IsInvalid)
_handle.SetHandleAsInvalid();
if(null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle",name));
__Error.WinIOError(errorCode, name);
createdNew = errorCode != Win32Native.ERROR_ALREADY_EXISTS;
SetHandleInternal(_handle);
private EventWaitHandle(SafeWaitHandle handle)
SetHandleInternal(handle);
[SecurityPermissionAttribute(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static EventWaitHandle OpenExisting(string name)
#if !FEATURE_PAL
return OpenExisting(name, EventWaitHandleRights.Modify | EventWaitHandleRights.Synchronize);
[SecurityPermissionAttribute(SecurityAction.LinkDemand,Flags=SecurityPermissionFlag.UnmanagedCode)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static EventWaitHandle OpenExisting(string name, EventWaitHandleRights rights)
// !FEATURE_PAL
if (name == null)
throw new ArgumentNullException("name", Environment.GetResourceString("ArgumentNull_WithParamName"));
if(name.Length
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "name");
if(null != name && System.IO.Path.MAX_PATH & name.Length)
throw new ArgumentException(Environment.GetResourceString("Argument_WaitHandleNameTooLong",name));
#if FEATURE_PAL
SafeWaitHandle myHandle = Win32Native.OpenEvent(Win32Native.EVENT_MODIFY_STATE | Win32Native.SYNCHRONIZE, false, name);
SafeWaitHandle myHandle = Win32Native.OpenEvent((int) rights, false, name);
if (myHandle.IsInvalid)
int errorCode = Marshal.GetLastWin32Error();
if(Win32Native.ERROR_FILE_NOT_FOUND == errorCode || Win32Native.ERROR_INVALID_NAME == errorCode)
throw new WaitHandleCannotBeOpenedException();
if(null != name && 0 != name.Length && Win32Native.ERROR_INVALID_HANDLE == errorCode)
throw new WaitHandleCannotBeOpenedException(Environment.GetResourceString("Threading.WaitHandleCannotBeOpenedException_InvalidHandle",name));
//this is for passed through Win32Native Errors
__Error.WinIOError(errorCode,"");
return new EventWaitHandle(myHandle);
public bool Reset()
bool res = Win32Native.ResetEvent(safeWaitHandle);
__Error.WinIOError();
public bool Set()
bool res = Win32Native.SetEvent(safeWaitHandle);
__Error.WinIOError();
#if !FEATURE_PAL
public EventWaitHandleSecurity GetAccessControl()
return new EventWaitHandleSecurity(safeWaitHandle, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
public void SetAccessControl(EventWaitHandleSecurity eventSecurity)
if (eventSecurity == null)
throw new ArgumentNullException("eventSecurity");
eventSecurity.Persist(safeWaitHandle);
再来看下ManualResetEvent的代码
namespace System.Threading {
using System.Security.P
using System.Runtime.InteropS
[HostProtection(Synchronization=true, ExternalThreading=true)]
[System.Visible(true)]
public sealed class ManualResetEvent : EventWaitHandle
public ManualResetEvent(bool initialState) : base(initialState,EventResetMode.ManualReset){}
其实这两个的差别就是AutoResetEvent是base(initialState,EventResetMode.AutoReset)而ManualResetEvent是base(initialState,EventResetMode.ManualReset).
AutoResetEvent是操作单个线程的,而ManualResetEvent可以操作多个线程.
AutoResetEvent开发示例
在主线程运行后,新开一个新线程,由新线程来控制主线程的等待和执行.
//===============================================================================
//作者:Spring Yang
//===============================================================================
namespace TestMultipleThread
using System.Collections.G
using System.T
public class ThreadWork
private MainContext mainC
private ContextCache contextC
public ThreadWork()
contextCache = ContextCache.GetContextCache();
mainContext = contextCache.GetContextByUserId("001");
public void Sum()
Console.WriteLine(string.Format("this is thread ID {0}
execute", Thread.CurrentThread.ManagedThreadId));
for (int i = 0; i & 10; i++)
Thread.Sleep(10);
if (mainContext != null && mainContext.IsCrawlWait == false)
mainContext.IsNTFSEvent =
while (mainContext.IsCrawlWait)
Thread.Sleep(25);
Console.WriteLine("main thread is wait");
Thread.Sleep(10000);
Console.WriteLine("main thread is start");
mainContext.IsNTFSEvent =
mainContext.SetThread();
class Program
public static void Main()
MainContext mainContext = new MainContext("001");
mainContext.Save();
//新开一个线程
ThreadWork threadWork = new ThreadWork();
ThreadStart myThreadDelegate = new ThreadStart(threadWork.Sum);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
for (int i = 0; i & 100; i++)
if (mainContext.IsNTFSEvent)
mainContext.ThreadWait();
Thread.Sleep(10);
Console.WriteLine("main Thread continue");
Thread.Sleep(100000);
public void WriteMessage()
Console.WriteLine("Stop the main thread.");
public class MainContext
public string UserId { }
//设置 AutoResetEvent
public AutoResetEvent WaitE
public ContextCache contextC
//设置线程等待
public void ThreadWait()
if (WaitEvent == null) WaitEvent = new AutoResetEvent(false);
if (IsNTFSEvent)
IsCrawlWait =
WaitEvent.WaitOne();
public MainContext(string userID)
UserId = userID;
IsCrawlWait =
IsNTFSEvent =
contextCache = ContextCache.GetContextCache();
public void Save()
contextCache.Save(UserId, this);
public void SetThread()
if (!IsNTFSEvent && IsCrawlWait)
IsCrawlWait =
WaitEvent.Set();
public bool IsCrawlWait { }
public bool IsNTFSEvent { }
//单例模式,保存到内存中
public class ContextCache
public Dictionary&string, MainContext& dicMainContext = new Dictionary&string, MainContext&();
public void Save(string userId, MainContext mainContext)
dicMainContext.Add(userId, mainContext);
private static ContextCache singleContextC
public MainContext GetContextByUserId(string userId)
dicMainContext.TryGetValue(userId, out context);
private ContextCache()
public static ContextCache GetContextCache()
if (singleContextCache == null)
singleContextCache = new ContextCache();
return singleContextC
2、 地址:&
欢迎各位参与讨论,如果觉得对你有帮助,请点击&&& 推荐下,万分谢谢.
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
阅读(...) 评论()

我要回帖

更多关于 timesetevent使用实例 的文章

 

随机推荐