|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Monitor.Pulse allows thread race“The thread that currently owns the lock on the specified object invokes this method to signal the next thread in line for the lock. Upon receiving the pulse, the waiting thread is moved to the ready queue. When the thread that invoked Pulse releases the lock, the next thread in the ready queue (which is not necessarily the thread that was pulsed) acquires the lock.†Evidence shows that when thread A pulses an object for which thread B is waiting within a locked region of that object, and then thread A leaves the locked region of that object, thread A can repossess the object's locked region before thread B demonstrates ownership of that region. This seems to contradict MSDN notes above. Given: Thread B performs: lock(x) { ... Monitor.Wait(x) ... } Thread A performs: while(1) { lock(x) { ... Monitor.Pulse(x) ... } } Thread B will be starved out waiting for the mutex on x and there is no sequencing guarantee that thread B will finish executing before thread A reaquires the mutex. Is this a bug or intended behavior? -- Tom Hintz On 2007-10-31 15:51:00 -0700, m***@comsquared.com <m***@comsquared.com> said:
> [...] I don't know enough about the Monitor class to answer the specific > Given: > Thread B performs: lock(x) { ... Monitor.Wait(x) ... } > > Thread A performs: while(1) { lock(x) { ... Monitor.Pulse(x) ... } } > > Thread B will be starved out waiting for the mutex on x and there is no > sequencing guarantee that thread B will finish executing before thread A > reaquires the mutex. Is this a bug or intended behavior? question. However, assuming it works in conjunction with the usual thread synchronization and scheduling mechanisms, then I would expect thread A to continue running until it explicitly blocks or exhausts its timeslice. So thread B won't get to acquire the lock until that point. If thread A still has the lock when its timeslice runs out, thread B still won't be able to acquire the lock. The docs might not be very clear on that, but it does seem to me to be a reasonable expectation based on how the rest of Windows works. Assuming the other threads are all of the same priority as thread A, then calling Sleep(0) in thread A after releasing the lock should allow other threads to get their chance at it. If those other threads are of lower priority, then calling Sleep(1) would be necessary. I can't say for sure what Microsoft would say, but assuming the intent is for Monitor to be reasonably lightweight, I would call this "intended behavior". The alternative is for Monitor to have to do extra work to decide what happens when a lock is released or acquired and/or always yield to other threads when releasing a lock, either of which could impair performance when not needed. Pete We rather guess that's what happens now, but until recently it appeared to
behave like thread B wasn't in the queue for the lock at the time of the pulse(), so A got the lock as intended. This matched our interpretation of the docs. -- Show quoteTom Hintz "Peter Duniho" wrote: > ... I would expect > thread A to continue running until it explicitly blocks or exhausts its > timeslice. So thread B won't get to acquire the lock until that point. > |
|||||||||||||||||||||||