does Monitor.Wait Needs synchronization?

前端 未结 3 923
予麋鹿
予麋鹿 2020-12-11 17:05

I have developed a generic producer-consumer queue which pulses by Monitor in the following way:

the enqueue :

    public void EnqueueTask(T task)
           


        
3条回答
  •  我在风中等你
    2020-12-11 17:55

    The proper way to view Monitor.Wait and Monitor.Pulse/PulseAll is not as providing a means of waiting, but rather (for Wait) as a means of letting the system know that the code is in a waiting loop which can't exit until something of interest changes, and (for Pulse/PulseAll) as a means of letting the system know that code has just changed something that might cause satisfy the exit condition some other thread's waiting loop. One should be able to replace all occurrences of Wait with Sleep(0) and still have code work correctly (even if much less efficiently, as a result of spending CPU time repeatedly testing conditions that haven't changed).

    For this mechanism to work, it is necessary to avoid the possibility of the following sequence:

    • The code in the wait loop tests the condition when it isn't satisfied.

    • The code in another thread changes the condition so that it is satisfied.

    • The code in that other thread pulses the lock (which nobody is yet waiting on).

    • The code in the wait loop performs a Wait since its condition wasn't satisfied.

    The Wait method requires that the waiting thread have a lock, since that's the only way it can be sure that the condition it's waiting upon won't change between the time it's tested and the time the code performs the Wait. The Pulse method requires a lock because that's the only way it can be sure that if another thread has "committed" itself to performing a Wait, the Pulse won't occur until after the other thread actually does so. Note that using Wait within a lock doesn't guarantee that it's being used correctly, but there's no way that using Wait outside a lock could possibly be correct.

    The Wait/Pulse design actually works reasonably well if both sides cooperate. The biggest weaknesses of the design, IMHO, are (1) there's no mechanism for a thread to wait until any of a number of objects is pulsed; (2) even if one is "shutting down" an object such that all future wait loops should exit immediately (probably by checking an exit flag), the only way to ensure that any Wait to which a thread has committed itself will get a Pulse is to acquire the lock, possibly waiting indefinitely for it to become available.

提交回复
热议问题