This suggests that there are situations where Wait and Pulse provide a simpler solution than wait commands. In general, this happens where:
- The waiter, not the notifier, decides when to unlock
- The blocking condition includes a simpler flag (possibly several variables)
In these situations, you can still use wait descriptors, but Wait / Pulse tends to be simpler. The great thing about Wait / Pulse is that Wait releases the underlying lock while waiting. For example, in the following example, we read _x and _y within the security of the lock - and yet this lock is released while waiting for another thread to update these variables:
lock (_locker) { while (_x < 10 && _y < 20) Monitor.Wait (_locker); }
Another thread can then update _x and _y atomically (due to blocking), and then Pulse to signal the waiter:
lock (_locker) { _x = 20; _y = 30; Monitor.Pulse (_locker); }
The disadvantage of Wait / Pulse is that it is easier to make a mistake and make a mistake (for example, updating a variable and forgetting the momentum). In situations where a wait-handling program is equally simple for a Wait / Pulse program, I would recommend going with wait commands for this reason.
In terms of efficiency / resource consumption (which I assume you pointed out), Wait / Pulse is usually faster and easier (since it has a managed implementation). However, this is rarely the case in practice. And at this point, Framework 4.0 includes the manually controlled versions of ManualResetEvent and Semaphore (ManualResetEventSlim and SemaphoreSlim).
Framework 4.0 also provides many additional synchronization options that reduce the need for Wait / Pulse:
- CountdownEvent
- Barrier
- PLINQ / Data Parallelism (AsParallel, Parallel.Invoke, Parallel.For, Parallel.ForEach)
- Tasks and Continuations
All of them are much higher than Wait / Pulse, and IMO is preferable for writing reliable and supported code (provided that they solve the problem at hand).
Joe albahari
source share