Reputation: 229341
I have code that looks like something like this:
def startSearching(self):
self.searchingLock.acquire()
searching = self.searching
if self.searching:
self.searchingLock.release()
self.logger.error("Already searching!")
return False
self.searching = True
self.searchingLock.release()
#some more init code, then start the thread which
#constantly checks self.searching to determine when to stop
it's kind of ugly, though. lots of acquires and releases. this looks prettier:
def startSearching(self):
with self.searchingLock:
if self.searching:
self.logger.error("Already searching!")
return False
self.searching = True
#some more init code, then start the thread which
#constantly checks self.searching to determine when to stop
but this keeps the lock longer than strictly necessary, espcially if self.logger.error
takes a while (like if it writes to disk, which it does). is there any middle ground between holding the lock as little as possible but having prettier code?
Upvotes: 7
Views: 4165
Reputation: 25680
How about wrapping the variable & lock in a class:
class LockedVariable(object):
def __init__(self, value, lock=None):
self._value = value
self._lock = lock if lock else threading.RLock()
self._locked = false:
@property
def locked(self):
return self._locked
def assign(self, value):
with self:
self._value = value
def release():
self._locked = False
return self._lock.release()
def __enter__(self):
self._lock.__enter__()
self._locked = True
return self._value
def __exit__(self, *args, **kwargs):
if self._locked:
self._locked = False
return self._lock.__exit__(*args, **kwargs)
And use as this:
locked_dict = LockedVariable({})
with locked_dict as value:
value['answer'] = 42
if locked_dict.locked:
locked_dict.release()
print 'eureka! :)'
return
if locked_dict.locked:
print 'bahh! :('
Comment:
I sometimes use boost::shared_ptr with a custom deleter to achieve the same thing, i.e. return an unlocked variable that's released when it goes out of scope.
Upvotes: 4
Reputation: 16308
Maybe you need to separate this logic like:
def initSearch(self):
with self.searchingLock:
if self.searching : raise SearchingError('AlreadySearching')
self.searching = True
def startSearching(self):
try: self.initSearch()
except SearchingError as error :
self.logger.error(error.message)
return False
#some more init code, then start the thread which
#constantly checks self.searching to determine when to stop
And additionaly you telling your searchingLock
the reason to release it automaticaly.
Upvotes: 6
Reputation: 2583
This will save you one "self.searchingLock.release()
" Guess it's not very pythonic or anything but it does the job
def startSearching(self):
self.searchingLock.acquire()
already_searching = self.searching
self.searching = True # Since it'll be true in both scenarios
self.searchingLock.release()
if already_searching:
self.logger.error("Already searching!")
return not already_searching
Upvotes: 1