[Python-bugs-list] [Bug #133665] Race condition in threading (Conditions)

noreply@sourceforge.net noreply@sourceforge.net
Fri, 23 Feb 2001 00:11:32 -0800


Bug #133665, was updated on 2001-Feb-22 13:15
Here is a current snapshot of the bug.

Project: Python
Category: Threads
Status: Open
Resolution: None
Bug Group: None
Priority: 4
Submitted by: nobody
Assigned to : tim_one
Summary: Race condition in threading (Conditions)

Details: Here is a race condition involving a _Condition() object cond and
a predicate called condition.

Thread A executes:
	cond.acquire()
	while not condition:
		cond.wait() <--

A goes into wait():
	waiter = _allocate_lock()
	waiter.acquire()
	self.__waiters.append(waiter)
	saved_state = self._release_save() <--

A finishes that last line and is interrupted by Thread B. A has released
cond's lock, so B continues (who was previously blocked at
cond.acquire()):
	cond.acquire()
	condition = 1
	cond.notifyAll()
	cond.release()

Back to A:
	if timeout is None:
		waiter.acquire() <--

A blocks here and completely misses the notifyAll() call. Even though it
called wait() before notifyAll(), it will now wait indefinatly for the next
notify()/notifyAll() call (which may be never).
I have run into this thread race bug in my program several times. A
POSIX-like atomic operation that releases a mutex and then grabs another
would be very useful here. Any suggestions?


Follow-Ups:

Date: 2001-Feb-23 00:11
By: tim_one

Comment:
You're going to have to work a lot harder to convince me that A can block. 
When cond.notifyAll() is executed, *all* the waiters in self.__waiters get
released.  It's certain that the waiter W allocated by A is in
self.__waiters at that point, because the append of W was protected by the
condvar lock, and B can't do cond.notifyAll() before it does
cond.acquire().

Therefore W is in self.__waiters when cond.notifyAll() is executed;
therefore cond.notifyAll()'s

for waiter in waiters: waiter.release()

executes W.release() in particular; therefore A's W.acquire() succeeds
sooner or later after that.

IOW, A cannot block on waiter.acquire(), because notifyAll() does
waiter.release().

I agree this *would* be a bug if A could block here, but, as above, I see
no reason to believe that it can.

Have reduced priority, and will close as NotABug tomorrow in the absence of
more info.
-------------------------------------------------------

For detailed info, follow this link:
http://sourceforge.net/bugs/?func=detailbug&bug_id=133665&group_id=5470