From: Dave C. <dj...@ob...> - 2002-07-12 02:33:38
|
On Wed, 10 Jul 2002, Kevin Jacobs wrote: > > Here is the current issue I'm working on. My app is > > single-threaded, so I'm a little confused as to why this happens: > > > > Traceback: > > Traceback (most recent call last): > [...] > > AssertionError: release() of un-acquire()d lock > > Never mind -- after looking at the code, it is clear why it is > blowing up. Can you explain what the unlock in the try-except block > is supposed to be doing? Can that if-statement be safely deleted? > > def close(self): > '''DB-API Cursor.close() > ''' > self._lock() > try: > if self._state == _CUR_CLOSED: > self._raise_error(Error, 'cursor is closed') > if self._state != _CUR_IDLE: > status = self._cmd.ct_cancel(CS_CANCEL_ALL) > if status == CS_SUCCEED: > self._unlock() > self._cmd = None > self._state = _CUR_CLOSED > finally: > self._unlock() The Python locks are being used in a reentrant manner to make the cursors thread safe. Each method which alters the cursor object protects itself by obtaining the lock at the start of the method and releasing at the end. Some sequences of cursor operations must be keep the cursor under the control of the same thread for the entire sequence of operations. If you look at the callproc() method you will see the beginning of such a sequence: if self._state == _CUR_IDLE: # At the start of a command acquire an extra lock - # when the cursor is idle again the extra lock will be # released. self._lock() And again in the execute() method: # At the start of a command acquire an extra lock - when # the cursor is idle again the extra lock will be # released. self._lock() If you look through the rest of the cursor code you will see places where the balancing _unlock() method is called. Once all of the results have been fetched. Following it through: * Each row is fetched via the fetchone() method via the function _fetch_rows(). If no row could be fetched (None returned) the cursor has reached the end of a result set. * At the end of result set the number of rows fetched is determined via the _fetch_rowcount() method. If this method discovers that there are no more result sets (CS_END_RESULTS from ct library) it sets the cursor idle and performs the balancing _unlock() Most of the other places in the code with do the balancing _unlock() are variants of this. When you close() a cursor while there are still outstanding results then the code does the _unlock(). Likewise when there is some sort of error returned by the Sybase ct_ library. Hope this makes things a bit more clear. - Dave -- http://www.object-craft.com.au |