Make a small function thread safe
Ian Kelly
ian.g.kelly at gmail.com
Mon Dec 19 01:57:43 EST 2011
On Sun, Dec 18, 2011 at 6:27 PM, Tim Delaney
<timothy.c.delaney at gmail.com> wrote:
> On 18 December 2011 19:52, RangerElf <gustavo.cordova at gmail.com> wrote:
>>
>> Which is why the original .acquire() ... .release() idiom was wrong, this
>> would better express the intent:
>>
>> try:
>> lock.acquire()
>> shared_container.append(...)
>> finally:
>> lock.release()
>
>
> No - this is very bad. The lock must be acquired outside the try: -
> otherwise if an exception is thrown while acquiring, you will try to release
> a lock that you have not acquired.
>
> Which again is why using with is a much better option - you can't make this
> kind of mistake.
Well, not unless you make the same mistake in the context manager itself.
from contextlib import contextmanager
@contextmanager
def bad_context_manager(lock):
try:
lock.acquire()
yield
finally:
lock.release()
class Lock(object):
def __init__(self):
self.is_locked = False
def acquire(self):
assert False
def release(self):
assert self.is_locked, "Tried to release lock without acquiring it"
with bad_context_manager(Lock()):
pass
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/contextlib.py", line 17, in __enter__
return self.gen.next()
File "<stdin>", line 7, in bad_context_manager
File "<stdin>", line 7, in release
AssertionError: Tried to release lock without acquiring it
Perhaps a (small) reason to avoid the contextmanager decorator and
implement __enter__ and __exit__ instead.
More information about the Python-list
mailing list