考虑以下模式:
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();
}
此模式的目的是允许外部消费者等待某个事件(例如 - 消息到达)。不在课堂内调用WaitForNextEvent
。
举一个应该熟悉的例子,考虑System.Diagnostics.Process
。它公开了一个Exited
事件,但它也公开了一个WaitForExit
方法,它允许调用者同步等待,直到进程退出。这就是我想在这里实现的目标。
我需要signal.Reset()
的原因是,如果线程在 WaitForNextEvent
之后调用signal.Set()
(或者换句话说,如果{{1} <}没有线程在等待时被调用),它会立即返回,因为事件已经先前已经发出信号。
.Set
之前发出呼叫WaitForNextEvent()
的话题?如果没有,那么实施signal.Reset()
方法的其他解决方案是什么?答案 0 :(得分:6)
请使用以下代码:
,而不是使用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();
}
然后改变你的代码:
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();
}
答案 1 :(得分:1)
无法保证。这样:
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();
不会在我的系统上打印“已执行工作项”。如果我在Thread.Sleep
和Set
之间添加Reset
,则会将其打印出来。请注意,这与处理器有关,因此您可能必须创建大部分线程来“填充”CPU。请注意,在我的电脑上,它可以在50%的时间内重现: - )
退出:
readonly object mylock = new object();
然后在某处:
lock (mylock)
{
// Your code goes here
}
和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;
}
请注意,lock
构造与async
/ await
不兼容(因为几乎不是.NET的所有锁定原语)
答案 2 :(得分:1)
我会使用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();
}
当代码调用SetResult
时,输入WaitForNextEvent
的新代码无法获取正在发出信号的TaskCompletionSource
。
答案 3 :(得分:0)
我相信不能保证。
但是,我的逻辑流程并不理解。如果主线程Set
是信号,为什么要等到信号到达目的地?在等待的那个线程中继续你的“后置信号设置”逻辑不是更好吗?
如果你不能这样做,我建议你使用第二个WaitHandle
来发信号通知第二个线程已经发出信号。但我看不出这种策略的任何优点。