問題描述
我什麼時候會使用 AutoResetEvent 和 ManualResetEvent 而不是 Monitor.Wait()/Monitor.Pulse()? (When would I use AutoResetEvent and ManualResetEvent instead of Monitor.Wait()/Monitor.Pulse()?)
它們似乎都實現了相同的目的。我什麼時候會選擇一個而不是另一個?
參考解法
方法 1:
Use the events when you've got a thread that is waiting on one of or all of a number of events to do something.
Use the monitor if you want to restrict access to a data structure by limiting how many threads can access it.
Monitors usually protect a resource, whereas events tell you something's happening, like the application shutting down.
Also, events can be named (see the OpenExisting method), this allows them to be used for synchronization across different processes.
方法 2:
In my opinion, it's better to use Monitor if you can, Monitor.Wait and Monitor.Pulse/PulseAll are used for signalling between threads (as are Manual/AutoResetEvent) however Monitor is quicker, and doesn't use a native system resource. Also apparently Monitor is implemented in user mode and is managed, whereas Manual/AutoResetEvents require switching to kernel mode and p/invoke out to native win32 calls that use a wait handle.
There are situations where you would need to use Manual/AutoResetEvent, for example, to signal between processes you can use named events, and I guess to signal native threads in your app.
I am just regurgitating what I have read in this excellent article about threading.
The whole article is worth reading, however the link takes you to the wait handle section that details the events and monitor wait/pulse.
方法 3:
You would use a WaitHandle
when you want a thread to send or receive a binary signal without the need for a critical section. Monitor.Wait
and Monitor.Pulse
on the other hand require a critical section. Like most of the synchronization mechanisms in the BCL there is some overlap in how a the two you mentioned can be used. But, do not think for a moment that they fulfill the same purpose.
Monitor.Wait
and Monitor.Pulse
are a much more primitive synchronization mechanism than an MRE or ARE. In fact, you can actually build an MRE or ARE using nothing more than the Monitor
class. The most important concept to understand is how the Monitor.Wait
and WaitHandle.WaitOne
methods differ. Wait
and WaitOne
will both put the thread in the WaitSleepJoin
state which means the thread becomes idle and only responds to either a Thread.Interrupt
or the respective Pulse
or Set
call. But, and this is a major difference, Wait
will leave a critical section and reacquire it in an atomic manner. WaitOne
simply cannot do this. It is a difference so fundamental to the way these synchronization mechanisms behave that defines the scenarios in which they can be used.
In most situations you would choose an MRE or ARE. These satisfy most situations where one thread needs to receive a signal from another. However, if you want to create your own signaling mechanism then you would need to use Wait
and Pulse
. But, again, the .NET BCL has most of the popular signaling mechanisms covered already. The following signaling mechanisms already exist1.
- ManualResetEvent (or ManualResetEventSlim)
- AutoResetEvent
- Semaphore (or SemaphoreSlim)
- EventWaitHandle
- CountdownEvent
- Barrier
1An honorable mention goes to the BlockingCollection
class. It is not a signaling mechanisms per se, but it does have the qualities of a signaling mechanism with the added benefit that you can attach data to the signal. In this case the signal means that an item is available in the collection and the data associated with that signal is the item itself.
方法 4:
This tutorial has detailed descriptions of what you'll need to know: http://www.albahari.com/threading/
In particular, this will cover the XXXResetEvent classes, http://www.albahari.com/threading/part2.aspx
and this will cover Wait/Pulse : http://www.albahari.com/threading/part4.aspx#_Wait_and_Pulse
(by NabilS、Scott Langham、Matt、Brian Gideon、torial)