Еще более легкое решение, вы можете попробовать, который использует класс Monitor для блокировки и разблокировки объектов ниже. Тем не менее, я не так доволен рассказом об очистке этой версии ReleaseasingAutoResetEvent, так как на мониторе может содержаться ссылка на нее и поддерживать ее на неопределенное время, если она не настроена должным образом.
Есть несколько ограничений/gotchas с этой реализацией. Во-первых, поток, который создает этот объект, будет единственным, который сможет сигнализировать об этом вызовом Set; другие потоки, которые пытаются сделать то же самое, получат исключение SynchronizationLockException. Во-вторых, поток, создавший его, никогда не сможет ждать его успешно, так как он уже владеет блокировкой. Это будет эффективным решением, если у вас есть только один управляющий поток и несколько других ожидающих потоков.
public static class Example
{
private static volatile bool stopRunning;
private static ReleasingAutoResetEvent myEvent;
public static void RunExample()
{
using (Example.myEvent = new ReleasingAutoResetEvent())
{
WaitCallback work = new WaitCallback(WaitThread);
for (int i = 0; i < 5; ++i)
{
ThreadPool.QueueUserWorkItem(work, i.ToString());
}
Thread.Sleep(500);
for (int i = 0; i < 3; ++i)
{
Example.myEvent.Set();
Thread.Sleep(5000);
}
Example.stopRunning = true;
Example.myEvent.Set();
}
}
private static void WaitThread(object state)
{
while (!Example.stopRunning)
{
Example.myEvent.WaitOne();
Console.WriteLine("Thread {0} is released!", state);
}
}
}
public sealed class ReleasingAutoResetEvent : IDisposable
{
private volatile object lockObject = new object();
public ReleasingAutoResetEvent()
{
Monitor.Enter(this.lockObject);
}
public void Set()
{
object objectToSignal = this.lockObject;
object objectToLock = new object();
Monitor.Enter(objectToLock);
this.lockObject = objectToLock;
Monitor.Exit(objectToSignal);
}
public void WaitOne()
{
object objectToMonitor = this.lockObject;
Monitor.Enter(objectToMonitor);
Monitor.Exit(objectToMonitor);
}
public bool WaitOne(int millisecondsTimeout)
{
object objectToMonitor = this.lockObject;
bool succeeded = Monitor.TryEnter(objectToMonitor, millisecondsTimeout);
if (succeeded)
{
Monitor.Exit(objectToMonitor);
}
return succeeded;
}
public bool WaitOne(TimeSpan timeout)
{
object objectToMonitor = this.lockObject;
bool succeeded = Monitor.TryEnter(objectToMonitor, timeout);
if (succeeded)
{
Monitor.Exit(objectToMonitor);
}
return succeeded;
}
public void Dispose()
{
Monitor.Exit(this.lockObject);
}
}
[Monitor.Pulse] (http://msdn.microsoft.com/en-us/library/system.threading.monitor (v = vs.110) .aspx)? –
@LB: Я думаю, вы имеете в виду ['Monitor.PulseAll()'] (http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulseall (v = vs.110) .aspx) –
Monitor.PulseAll() требует, чтобы у вас была блокировка объекта. У AutoResetEvent нет таких требований для своего соответствующего метода Set(). Я не могу себе представить, как построить мой класс в конструкции монитора ??? –