C#.net线程中WaitHandle
背后的基本概念是什么?
它的用途是什么?
什么时候用?
其中有 WaitAll 和 WaitAny 方法的用途是什么?
答案 0 :(得分:60)
每当您想要控制应用程序中多个线程的执行时。虽然这不仅意味着只有一个线程增加计数器;但让线程开始/停止或暂停一个事件。
请参阅WaitHandles - Auto/ManualResetEvent and Mutex
<强> - 编辑 - 强>
WaitHandle
是您“用来”控制线程执行的机制。它不是关于在一个线程内无法访问的句柄;它在线程中使用它们。
这可能是一个很好的例子,但请耐心等待;想一想,一位女士给五个女孩五个不同的口哨,并告诉他们只要something
发生就吹哨子;这个过程是让每个女孩吹口哨,这位女士会知道是谁吹响了哨子。
现在,它不是为了分享彼此的口哨,它可能是为了女士,用它来“控制”执行或女孩吹口哨的过程。
因此,从技术上讲,这个过程将是:
WaitHandle.WaitAny(events);
.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();
}
}
答案 1 :(得分:30)
WaitHandle
是两个常用事件句柄的抽象基类:AutoResetEvent
和ManualResetEvent
。
这两个类都允许一个线程“发出信号”一个或多个其他线程。它们用于在线程之间同步(或序列化活动)。这是使用Set
和WaitOne
(或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
(从异步调用委托返回),WaitOne
允许您使当前线程等待异步操作完成。
如果未设置AutoResetEvent
或ManualResetEvent
,则调用WaitOne
将阻止调用线程,直到调用Set
为止。这两个类的不同之处仅在于AutoResetEvent
成功调用WaitOne
后“{1}}”取消设置“事件,使后续调用再次阻塞,直到Set
被调用。必须通过调用ManualResetEvent
明确“取消设置”Reset
。
WaitAll
和WaitAny
是WaitHandle
类上的静态方法,允许您指定要等待的WaitHandles
数组。 WaitAll
将阻止提供的句柄的所有 Set
,而WaitAny
只会阻止一个获得Set
{{1}} 1}}。
答案 2 :(得分:9)
这是一个抽象类,你不直接使用它。具体的派生类是ManualResetEvent,AutoResetEvent,Mutex和Semaphore。工具箱中用于实现线程同步的重要类。它们继承WaitOne,WaitAll和WaitAny方法,您可以使用它们来检测一个或多个线程发出等待条件的信号。
Manual / AutoResetEvent的典型使用场景是告诉线程退出或让线程发出信号表明它已经进展到一个重要的序列点。信号量可以帮助您限制执行操作的线程数。或者实现不应该与特定线程具有亲缘关系的线程同步。 Mutex用于将一段代码的所有权分配给一个线程,锁定语句通常也适用于那里。
已经有关于它的书籍。 Joe Duffy的Concurrent Programming in Windows是最新最好的。如果您考虑编写线程代码,强烈建议使用。
答案 3 :(得分:7)
想象一下,你有一个包含1000个项目的数组。您需要对每个项目进行一些处理。这项工作需要一些时间,但不受I / O限制。
例如,您可能需要使用每个项目来生成低带宽Web请求。您有足够的吞吐量来同时请求多个项目,并且每个Web请求中的延迟意味着一次执行一个可能需要比您想要的更长的时间。
进入并行编程的世界。今天,您可以通过多种方式处理此任务,WaitHandle
是其中的一个基本部分。即使您没有直接使用WaitHandle
,您选择的任何选项都可能依赖于WaitHandle
,例如幕后的WaitAll
或WaitAny
。
继续这个例子,假设你有一个典型的四核CPU。在这种情况下,同时拥有超过4个线程并没有多大意义。 * 所以4个线程,但1000个项目;你是做什么?
一个选项使用WaitAny
。你启动了4个线程,每次WaitAny
方法返回时你都会启动另一个,直到所有1000个项目都排队。请注意,这是WaitAny
的一个不好的示例,因为我们知道总共有多少项,并且可以以相同的速率访问任何项目。只有顺序访问时,WaitAny
才是最佳选择。还有其他类似的情况,WaitAny
可以很有意义。
另一个选项使用WaitAll
。您不是一次排队一个项目,而是为四个核心中的每个核心设置一个线程,为其分配不同的250个项目段。使用此选项,您可以使用WaitAll
等待所有处理完成。
*实际上,确实如此。 CPU通常会有一定的I / O时间,这样你就可以通过每个核心运行多个线程来做得更好。但这是另一个故事。
答案 4 :(得分:1)
这里有一些很长的答案。对于任何寻找简短回答的人:
Wait handle是一种让一个线程等到另一个线程到达某一点的机制。
您还可以等待多个线程和/或等待的多个线程,因此WaitOne
,WaitAll
和WaitAny
方法。通过选择其中一个类,还可以选择其中一个语义:Mutex
,Semaphore
,ManualResetEvent
,AutoResetEvent
,这些选项都有详细记录。