Mailing List Archive

[ python-Bugs-1746071 ] class mutex doesn't do anything atomically
Bugs item #1746071, was opened at 2007-07-02 00:49
Message generated for change (Comment added) made by ncoghlan
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1746071&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Python Library
Group: Python 2.5
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: David Benbennick (dbenbenn)
Assigned to: Nobody/Anonymous (nobody)
Summary: class mutex doesn't do anything atomically

Initial Comment:
>>> import mutex
>>> print mutex.mutex.testandset.__doc__
Atomic test-and-set -- grab the lock if it is not set,
return True if it succeeded.


The above docstring is wrong: the method is not atomic. This is easy to see by inspecting the method's code:

def testandset(self):
"""Atomic test-and-set -- grab the lock if it is not set,
return True if it succeeded."""
if not self.locked:
self.locked = 1
return True
else:
return False

Therefore, it is possible for two threads to lock the same mutex simultaneously. So the mutex module cannot be used for mutual exclusion.

The documentation for mutex says "The mutex module defines a class that allows mutual-exclusion via acquiring and releasing locks." [http://docs.python.org/lib/module-mutex.html]. Perhaps it would be a good idea to make the module actually do what the documentation says.

----------------------------------------------------------------------

>Comment By: Nick Coghlan (ncoghlan)
Date: 2007-07-31 23:18

Message:
Logged In: YES
user_id=1038590
Originator: NO

The docs may be misleading - they're missing a key comment from the source
code that suggests that this particular mutex is specifically for use with
the single threaded event scheduler in the sched module. On the other hand,
the module predates the thread module by more than a year, and the
threading module by about 7 years, so it may simply have failed to keep up
with the times.

The module as written definitely isn't thread-safe though (I suspect the
question of whether or not it should be hasn't really come up before, as
most new code just uses threading.Lock or threading.RLock for all its mutex
needs). Either the code needs to change or the docs - this question would
probably be best asked on python-dev (referencing this bug report).

----------------------------------------------------------------------

Comment By: David Benbennick (dbenbenn)
Date: 2007-07-04 07:26

Message:
Logged In: YES
user_id=95581
Originator: YES

I've attached a patch to mutex.py that fixes the bug by acquiring a lock
in testandset() and unlock(). After you apply the patch, the previous
attachment will run forever.
File Added: patch.txt

----------------------------------------------------------------------

Comment By: O.R.Senthil Kumaran (orsenthil)
Date: 2007-07-04 05:36

Message:
Logged In: YES
user_id=942711
Originator: NO

Thanks David, there is something 'interesting' being observed here.
At a point:
Calling testandset in thread 1, m.locked is False
Calling testandset in thread 0, m.locked is False
Thread 0 locked
Resetting, trying again

Another place:
Calling testandset in thread 1, m.locked is False
Calling testandset in thread 0, m.locked is False
Thread 0 locked
Thread 1 locked
Hah, all these threads locked at the same time: [0, 1]

My doubts are still with threading, but am unable to derive anything.
Should someone more experienced look into? Or mind taking this for
suggestions to c.l.p?



----------------------------------------------------------------------

Comment By: David Benbennick (dbenbenn)
Date: 2007-07-02 19:23

Message:
Logged In: YES
user_id=95581
Originator: YES

> How are you using mutex with threads, can you please provide some
information.

I'm attaching an example program that demonstrates two threads both
locking the same mutex at the same time.

> If muobj is an instance of mutex class.
> muobj.testandset() for process-a will set the lock.
> muobj.testandset() for process-b will be dealt with self.lock = True
and
> wont be able to set.

That isn't correct. It is possible for testandset to return True in both
thread-a and thread-b. What can happen is the following:

1) Thread a calls testandset(). It executes the line "if not
self.locked", and finds the result to be True.
2) The OS switches threads.
3) Thread b calls testandset(). It executes the line "if not
self.locked", and finds the result to be True.
4) Thread b sets "self.locked = 1" and returns True
5) Thread a sets "self.locked = 1" and returns True
File Added: ex.py

----------------------------------------------------------------------

Comment By: O.R.Senthil Kumaran (orsenthil)
Date: 2007-07-02 13:10

Message:
Logged In: YES
user_id=942711
Originator: NO

Hi David,
I just fired up the docs and found this:
"The mutex module defines a class that allows mutual-exclusion via
acquiring and releasing locks. It does not require (or imply) threading or
multi-tasking, though it could be useful for those purposes."

The docs dont say about threads using mutex object, but instead say if you
want to use threading you can use mutex obj.

How are you using mutex with threads, can you please provide some
information.

If muobj is an instance of mutex class.
muobj.testandset() for process-a will set the lock.
muobj.testandset() for process-b will be dealt with self.lock = True and
wont be able to set.

----------------------------------------------------------------------

You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1746071&group_id=5470
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/list-python-bugs%40lists.gossamer-threads.com