[英]AutoResetEvent Reset immediately after Set
Consider the following pattern:考虑以下模式:
private AutoResetEvent signal = new AutoResetEvent(false);
private void Work()
{
while (true)
{
Thread.Sleep(5000);
signal.Set();
//has a waiting thread definitely been signaled by now?
signal.Reset();
}
}
public void WaitForNextEvent()
{
signal.WaitOne();
}
The purpose of this pattern is to allow external consumers to wait for a certain event (eg - a message arriving).此模式的目的是允许外部消费者等待某个事件(例如 - 消息到达)。
WaitForNextEvent
is not called from within the class. WaitForNextEvent
不是从类内部调用的。
To give an example that should be familiar, consider System.Diagnostics.Process
.举一个应该很熟悉的例子,考虑
System.Diagnostics.Process
。 It exposes an Exited
event, but it also exposes a WaitForExit
method, which allows the caller to wait synchronously until the process exits.它暴露了一个
Exited
事件,但它也暴露了一个WaitForExit
方法,该方法允许调用者同步等待直到进程退出。 this is what I am trying to achieve here.这就是我想要在这里实现的目标。
The reason I need signal.Reset()
is that if a thread calls WaitForNextEvent
after signal.Set()
has already been called (or in other words, if .Set
was called when no threads were waiting), it returns immediately, as the event has already been previously signaled.究其原因,我需要
signal.Reset()
是,如果一个线程调用WaitForNextEvent
后signal.Set()
已经被调用(或者换句话说,如果.Set
当没有线程在等待被称为),它会立即返回,因为事件之前已经发出信号。
WaitForNextEvent()
will be signaled before signal.Reset()
is called?WaitForNextEvent()
将前信号signal.Reset()
被调用? If not, what are other solutions for implementing a WaitFor
method?WaitFor
方法的其他解决方案是什么?Instead of using AutoResetEvent
or ManualResetEvent
, use this:而不是使用
AutoResetEvent
或ManualResetEvent
,使用这个:
public sealed class Signaller
{
public void PulseAll()
{
lock (_lock)
{
Monitor.PulseAll(_lock);
}
}
public void Pulse()
{
lock (_lock)
{
Monitor.Pulse(_lock);
}
}
public void Wait()
{
Wait(Timeout.Infinite);
}
public bool Wait(int timeoutMilliseconds)
{
lock (_lock)
{
return Monitor.Wait(_lock, timeoutMilliseconds);
}
}
private readonly object _lock = new object();
}
Then change your code like so:然后像这样更改您的代码:
private Signaller signal = new Signaller();
private void Work()
{
while (true)
{
Thread.Sleep(5000);
signal.Pulse(); // Or signal.PulseAll() to signal ALL waiting threads.
}
}
public void WaitForNextEvent()
{
signal.Wait();
}
There is no guarantee.没有保证。 This:
这:
AutoResetEvent flag = new AutoResetEvent(false);
new Thread(() =>
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
Console.WriteLine("Work Item Started");
flag.WaitOne();
Console.WriteLine("Work Item Executed");
}).Start();
// For fast systems, you can help by occupying processors.
for (int ix = 0; ix < 2; ++ix)
{
new Thread(() => { while (true) ; }).Start();
}
Thread.Sleep(1000);
Console.WriteLine("Sleeped");
flag.Set();
// Decomment here to make it work
//Thread.Sleep(1000);
flag.Reset();
Console.WriteLine("Finished");
Console.ReadLine();
won't print "Work Item Executed" on my system.不会在我的系统上打印“已执行的工作项”。 If I add a
Thread.Sleep
between the Set
and the Reset
it prints it.如果我在
Set
和Reset
之间添加一个Thread.Sleep
它会打印它。 Note that this is very processor dependent, so you could have to create tons of threads to "fill" the CPUs.请注意,这非常依赖于处理器,因此您可能必须创建大量线程来“填充”CPU。 On my PC it's reproducible 50% of the times :-)
在我的 PC 上,它可以重复 50% 的时间:-)
For the Exited:对于退出:
readonly object mylock = new object();
then somewhere:然后某处:
lock (mylock)
{
// Your code goes here
}
and the WaitForExit
:和
WaitForExit
:
void WaitForExit()
{
lock (mylock) ;
// exited
}
void bool IsExited()
{
bool lockTacken = false;
try
{
Monitor.TryEnter(mylock, ref lockTacken);
}
finally
{
if (lockTacken)
{
Monitor.Exit(mylock);
}
}
return lockTacken;
}
Note that the lock
construct isn't compatible with async
/ await
(as aren't nearly all the locking primitives of .NET)请注意,
lock
结构与async
/ await
不兼容(因为几乎不是 .NET 的所有锁定原语)
I would use TaskCompletionSource
s:我会使用
TaskCompletionSource
s:
private volatile TaskCompletionSource<int> signal = new TaskCompletionSource<int>();
private void Work()
{
while (true)
{
Thread.Sleep(5000);
var oldSignal = signal;
signal = new TaskCompletionSource<int>()
//has a waiting thread definitely been signaled by now?
oldSignal.SetResult(0);
}
}
public void WaitForNextEvent()
{
signal.Task.Wait();
}
By the time that the code calls SetResult
, no new code entering WaitForNextEvent
can obtain the TaskCompletionSource
that is being signalled.通过该代码调用时
SetResult
,没有进入新的代码WaitForNextEvent
可以获得TaskCompletionSource
正在被通知。
I believe it is not guaranteed.我相信这是不能保证的。
However, your logic flow is not understood by me.但是,我不理解您的逻辑流程。 If your main thread
Set
s the signal, why should it wait until that signal reaches its destination?如果您的主线程
Set
是信号,为什么要等到该信号到达目的地? Wouldn't it be better to continue your "after signal set" logic in that thread which was waiting?在那个等待的线程中继续你的“后信号设置”逻辑不是更好吗?
If you cannot do that, I recommend you to use second WaitHandle
to signal the first thread that the second one has reveiced the signal.如果你不能这样做,我建议你使用第二个
WaitHandle
来通知第一个线程第二个已经接收到信号。 But I cannot see any pros of such a strategy.但我看不到这种策略的任何优点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.