WaitHandle的基本概念是什么?

C#.net线程中WaitHandle的基本概念是什么? 它的用途是什么? 何时使用它? 里面的WaitAllWaitAny方法有什么用?

每当你想要控制你的应用程序中的多个线程的执行。 虽然这不仅意味着只有一个线程递增计数器, 但让线程开始/停止或暂停一个事件。

请参阅WaitHandles – Auto / ManualResetEvent和Mutex

– 编辑 –

WaitHandle是您“使用”来控制线程执行的机制。 它不是关于在一个线程内不可访问的句柄; 它关于在线程中使用它们。

这可能是一个很好的例子,但请忍受我; 想想,一位女士给五个女孩五个不同的口哨,并告诉他们吹哨什么时候会发生, 过程是每个女孩吹口哨,女士会知道是谁吹的哨子。

现在,这不是关于彼此分享口哨,而是关于可能是为了女士,用它们来“控制”女孩吹口哨的执行或过程。

因此,技术上这个过程将是:

  1. 创build一个等待事件(ManualResetEvent对象)
  2. 注册事件, WaitHandle.WaitAny(events);
  3. 在线程完成操作后, .Set()会告诉WaitHandle“我已经完成了!”。

例如,从所提供的链接中考虑示例。 我已经添加了步骤来了解逻辑。 这些不是硬编码的步骤,但是你可以理解。

 class Test { static void Main() { //STEP 1: Create a wait handle ManualResetEvent[] events = new ManualResetEvent[10];//Create a wait handle for (int i=0; i < events.Length; i++) { events[i] = new ManualResetEvent(false); Runner r = new Runner(events[i], i); new Thread(new ThreadStart(r.Run)).Start(); } //STEP 2: Register for the events to wait for int index = WaitHandle.WaitAny(events); //wait here for any event and print following line. Console.WriteLine ("***** The winner is {0} *****", index); WaitHandle.WaitAll(events); //Wait for all of the threads to finish, that is, to call their cooresponding `.Set()` method. Console.WriteLine ("All finished!"); } } class Runner { static readonly object rngLock = new object(); static Random rng = new Random(); ManualResetEvent ev; int id; internal Runner (ManualResetEvent ev, int id) { this.ev = ev;//Wait handle associated to each object, thread in this case. this.id = id; } internal void Run() { //STEP 3: Do some work for (int i=0; i < 10; i++) { int sleepTime; // Not sure about the thread safety of Random... lock (rngLock) { sleepTime = rng.Next(2000); } Thread.Sleep(sleepTime); Console.WriteLine ("Runner {0} at stage {1}", id, i); } //STEP 4: Im done! ev.Set(); } } 

WaitHandle是两个常用事件句柄的抽象基类: AutoResetEventManualResetEvent

这两个类都允许一个线程“发送”一个或多个其他线程。 它们用于在线程之间同步(或序列化活动)。 这是使用SetWaitOne (或WaitAll )方法完成的。 例如:

主题1:

 // do setup work myWaitHandle.Set(); 

主题2:

 // do setup work myWaitHandle.WaitOne(); // this code will not continue until after the call to `Set` // in thread 1 completes. 

这是一个非常基本的例子,网上有很多这样的例子。 基本的想法是, WaitOne用于等待来自另一个线程的信号,指示发生了什么事情。 在AsyncWaitHandle (通过asynchronous调用委托返回)的情况下, WaitOne允许您导致当前线程等待asynchronous操作完成。

当没有设置AutoResetEventManualResetEvent ,对WaitOne将阻塞调用线程,直到调用Set 。 这两个类的区别仅在于,一旦成功调用WaitOneAutoResetEvent “解除”该事件,使得后续的调用再次被阻塞,直到Set被调用。 ManualResetEvent必须通过调用Reset明确“取消设置”。

WaitAllWaitAnyWaitHandle类的静态方法,允许您指定WaitHandles数组等待。 WaitAll将阻塞直到所有提供的句柄都被Set ,而WaitAny将只阻塞直到其中一个Set

这是一个抽象类,你不直接使用它。 具体派生类是ManualResetEvent,AutoResetEvent,Mutex和Semaphore。 在您的工具箱中实现线程同步的重要类。 它们inheritance了WaitOne,WaitAll和WaitAny方法,用它们来检测一个或多个线程是否表示等待状态。

Manual / AutoResetEvent的典型使用场景是告诉线程退出或者让线程发出已经进入重要序列点的信号。 信号量可以帮助您限制执行操作的线程数量。 或者实现不应该与特定线程相关的线程同步。 互斥体在那里将一段代码的所有权分配给一个线程,locking语句通常也适用于那里。

书已经写了关于它。 Joe Duffy 在Windows中的并行编程是最新和最好的。 强烈build议,如果你正在考虑编写线程代码。

WaitAll和WaitAny方法背后的想法是,当你有很多想要并行运行的任务时,这些方法非常有用。

例如,假设你必须做一个工作,需要你对一个数组中的1000个项目进行一些处理,这些项目需要并行处理。 一个典型的Core 2 Duo +超线程只有4个逻辑处理器,所以一次运行4个以上的线程并没有什么意义(事实上,它确实如此,但这又是一个故事 – 我们将现在假装并使用简单的“每个处理器一个线程”模型)。 所以4个线程,但1000个项目; 你是做什么?

一种select是使用WaitAny方法。 您启动了4个线程,并且每次WaitAny方法返回时都会启动另一个线程,直到所有1000个项目都排队。 请注意,这是WaitAny的一个不好的例子,因为你也可以把你的数组分成250个项目块。 但是,希望能给你和WaitAny有用的情况。 还有其他类似的情况,WaitAny可以很有意义。

但现在让我们回到4个线程的场景,每个线程处理来自1000条目数组的250个条目。 使用此选项,可以使用WaitAll方法等待所有处理完成。

这里有一些很长的答案。 对于任何寻找简短答案的人:

等待句柄是使一个线程等待另一个线程到达某个点的机制。

您也可以有多个等待的线程和/或多个正在等待的线程,因此有WaitOneWaitAllWaitAny方法。 通过select这些类中的一个,还可以使用多种语义选项: MutexSemaphoreManualResetEventAutoResetEvent ,这些都是有据可查的。