我已经阅读了关于这方面的文档,我想我明白了。AutoResetEvent在代码通过event.WaitOne()时重置,但ManualResetEvent不会。
这对吗?
我已经阅读了关于这方面的文档,我想我明白了。AutoResetEvent在代码通过event.WaitOne()时重置,但ManualResetEvent不会。
这对吗?
当前回答
我创建了简单的示例来阐明ManualResetEvent与AutoResetEvent的理解。
AutoResetEvent:让我们假设你有3个工作线程。如果这些线程中的任何一个调用WaitOne(),所有其他两个线程将停止执行并等待信号。我假设他们正在使用WaitOne()。它就像;如果我不工作,没人会工作。在第一个例子中你可以看到
autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();
当你调用Set()时,所有线程都将工作并等待信号。1秒后,我发送第二个信号,它们执行并等待(WaitOne())。想想这些家伙是足球队的球员,如果一个球员说我会等到经理叫我,其他人会等到经理告诉他们继续(Set())
public class AutoResetEventSample
{
private AutoResetEvent autoReset = new AutoResetEvent(false);
public void RunAll()
{
new Thread(Worker1).Start();
new Thread(Worker2).Start();
new Thread(Worker3).Start();
autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();
Console.WriteLine("Main thread reached to end.");
}
public void Worker1()
{
Console.WriteLine("Entered in worker 1");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker1 is running {0}", i);
Thread.Sleep(2000);
autoReset.WaitOne();
}
}
public void Worker2()
{
Console.WriteLine("Entered in worker 2");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker2 is running {0}", i);
Thread.Sleep(2000);
autoReset.WaitOne();
}
}
public void Worker3()
{
Console.WriteLine("Entered in worker 3");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker3 is running {0}", i);
Thread.Sleep(2000);
autoReset.WaitOne();
}
}
}
在这个例子中,你可以清楚地看到,当你第一次点击Set()时,它会让所有线程离开,然后在1秒后它会通知所有线程等待!一旦你再次设置它们,不管它们在里面调用WaitOne(),它们都会继续运行,因为你必须手动调用Reset()来停止它们。
manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();
这更多的是裁判和球员之间的关系,不管任何球员受伤了,等待比赛,其他人都将继续工作。如果裁判说等待(Reset()),那么所有球员将等待下一次信号。
public class ManualResetEventSample
{
private ManualResetEvent manualReset = new ManualResetEvent(false);
public void RunAll()
{
new Thread(Worker1).Start();
new Thread(Worker2).Start();
new Thread(Worker3).Start();
manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();
Console.WriteLine("Main thread reached to end.");
}
public void Worker1()
{
Console.WriteLine("Entered in worker 1");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker1 is running {0}", i);
Thread.Sleep(2000);
manualReset.WaitOne();
}
}
public void Worker2()
{
Console.WriteLine("Entered in worker 2");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker2 is running {0}", i);
Thread.Sleep(2000);
manualReset.WaitOne();
}
}
public void Worker3()
{
Console.WriteLine("Entered in worker 3");
for (int i = 0; i < 5; i++) {
Console.WriteLine("Worker3 is running {0}", i);
Thread.Sleep(2000);
manualReset.WaitOne();
}
}
}
其他回答
摘自c# 3.0果壳书,由 约瑟夫Albahari
c#线程-免费电子书
ManualResetEvent是AutoResetEvent的变体。它的不同之处在于它不会在线程通过WaitOne调用后自动重置,因此功能类似于gate:调用Set打开gate,允许WaitOne在gate处通过任意数量的线程;调用Reset会关闭大门,可能会导致排队等候的人越来越多,直到下一个门被打开。
可以使用布尔值“gateOpen”字段(使用volatile关键字声明)结合“spin-sleep”来模拟此功能——重复检查标志,然后小睡一小段时间。
ManualResetEvents有时用于表示特定操作已完成,或线程已完成初始化并准备执行工作。
如果你想理解AutoResetEvent和ManualResetEvent,你需要理解的不是线程,而是中断!
. net希望尽可能地实现底层编程。
中断是在低级编程中使用的,它相当于一个信号从低电平变成高电平(反之亦然)。当这种情况发生时,程序中断其正常执行,并将执行指针移到处理此事件的函数上。
当中断发生时,要做的第一件事是重置它的状态,因为硬件是这样工作的:
a pin is connected to a signal and the hardware listen for it to change (the signal could have only two states). if the signal changes means that something happened and the hardware put a memory variable to the state happened (and it remain like this even if the signal change again). the program notice that variable change states and move the execution to a handling function. here the first thing to do, to be able to listen again this interrupt, is to reset this memory variable to the state not-happened.
这就是ManualResetEvent和AutoResetEvent之间的区别。 如果ManualResetEvent发生,我不重置它,下次发生时,我将无法收听它。
是的。这是绝对正确的。
您可以将ManualResetEvent视为指示状态的一种方式。某些东西打开(设置)或关闭(重置)。有一定持续时间的事件任何等待该状态发生的线程都可以继续。
AutoResetEvent更类似于信号。这是发生了什么事的一个迹象。没有任何持续时间的事件。通常情况下(但不一定)发生的“事情”很小,需要由单个线程处理——因此在单个线程消耗事件后自动重置。
AutoResetEvent在内存中维护一个布尔变量。如果布尔变量为假,则阻塞线程,如果布尔变量为真,则解除阻塞线程。
实例化AutoResetEvent对象时,在构造函数中传递默认值布尔值。下面是实例化AutoResetEvent对象的语法。
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
WaitOne方法
该方法阻塞当前线程,等待其他线程发出信号。WaitOne方法将当前线程置于Sleep线程状态。WaitOne方法如果接收到信号则返回true,否则返回false。
autoResetEvent.WaitOne();
WaitOne方法的秒重载等待指定的秒数。如果它没有得到任何信号,线程继续它的工作。
static void ThreadMethod()
{
while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
{
Console.WriteLine("Continue");
Thread.Sleep(TimeSpan.FromSeconds(1));
}
Console.WriteLine("Thread got signal");
}
我们通过传递2秒作为参数来调用WaitOne方法。在while循环中,它等待信号2秒,然后继续它的工作。当线程得到信号时,WaitOne返回true并退出循环并打印“线程得到信号”。
设置方法
方法将信号发送给等待线程以继续其工作。下面是调用Set方法的语法。
autoResetEvent.Set();
ManualResetEvent在内存中维护一个布尔变量。当布尔变量为false时,它阻塞所有线程,当布尔变量为true时,它解除阻塞所有线程。
当我们实例化ManualResetEvent时,我们用默认的布尔值初始化它。
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
在上面的代码中,我们用false值初始化ManualResetEvent,这意味着所有调用WaitOne方法的线程都将阻塞,直到一些线程调用Set()方法。
如果我们初始化ManualResetEvent的值为true,那么所有调用WaitOne方法的线程都不会阻塞,可以继续执行。
WaitOne方法
该方法阻塞当前线程,等待其他线程发出信号。如果它接收到信号,则返回true否则返回false。
下面是调用WaitOne方法的语法。
manualResetEvent.WaitOne();
在WaitOne方法的第二次重载中,我们可以指定当前线程等待信号的时间间隔。如果在time internal内,它没有接收到信号,则返回false并进入下一行方法。
下面是按时间间隔调用WaitOne方法的语法。
bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
我们已经在WaitOne方法中指定了5秒。如果manualResetEvent对象在5秒内没有接收到信号,它将issignals变量设置为false。
设置方法
此方法用于向所有等待线程发送信号。Set()方法将ManualResetEvent对象布尔变量设置为true。所有等待的线程都被解除阻塞并继续执行。
下面是调用Set()方法的语法。
manualResetEvent.Set();
复位方法
一旦我们在ManualResetEvent对象上调用Set()方法,它的布尔值仍然为true。要重置值,可以使用reset()方法。重置方法将布尔值更改为false。
下面是调用Reset方法的语法。
manualResetEvent.Reset();
如果要多次向线程发送信号,必须在调用Set方法后立即调用Reset方法。
想象一下AutoResetEvent将WaitOne()和Reset()作为单个原子操作执行。
AutoResetEvent还保证只释放一个等待线程。