[python-uk] [pyconuk] Minimalistic software transactional memory
Michael Sparks
ms at cerenity.org
Tue Dec 11 18:15:51 CET 2007
Hi Richard,
On Tuesday 11 December 2007 13:36, Richard Taylor wrote:
> I don't think that you can rely on the threadsafety of these functions.
> Even if they are threadsafe in C Python (which I doubt that 'set' is), the
> locking in Jython in more fine grained and would likely catch you out.
It's perhaps worth noting in the version of the code I posted, in this thread,
where it said...
"""What key areas appear least threadsafe, and any general suggestions
around that."""
...I knew that set and using were not threadsafe, but wondered about other
parts. I perhaps should've been more explicit on that point. (I wanted to
simply post some ideas which showed the core logic without locking. Perhaps a
mistake :)
Anyhow, the current version is here:
https://kamaelia.svn.sourceforge.net/svnroot/kamaelia/branches/private_MPS_Scratch/Bindings/STM/Axon/STM.py
In that version, "set" now looks like this:
def set(self, key, value):
success = False
if self.lock.acquire(0):
try:
if not (self.store[key].version > value.version):
self.store[key] = Value(value.version+1,
copy.deepcopy(value.value),
self, key)
value.version= value.version+1
success = True
finally:
self.lock.release()
else:
raise BusyRetry
if not success:
raise ConcurrentUpdate
and "using" has changed to "usevar: (using now relates to a collection)
def usevar(self, key):
try:
return self.get(key)
except KeyError:
if self.lock.acquire(0):
try:
self.store[key] = Value(0, None,self,key)
finally:
self.lock.release()
else:
raise BusyRetry
return self.get(key)
Since mutations of the store rely on acquiring the lock on the store, that
should be safe(r). User code doesn't have to worry about locks however -
which is course the point of the code :-)
The reason for specifically using the acquire(0) call rather than acquire()
call is because I want it to fail hard if the lock can't be acquired. I know
it'd be nicer to have a finer grained lock here, but I'm personally primarily
going to be using this for rare operations rather than common operations.
These locks above are of course in relation to write locking. I'll think about
the read locking you've suggested.
Your locking looks incorrect on using since it both allows reading and writing
of the store. (retrieve value & if not present create & initialise)
I also think the independent locks are a misnomer, but they're useful for
thinking about it.
> I would suggest that you should routinely wrap shared datamodels like these
> in thread locks to be certain about things.
Indeed. It makes the code look worse, so for this example I was really after
suggestions (like yours :-) of "OK, where does this break badly" as well as
"does the logic look sane?".
> I would also suggest that a small change to the Value class would make it
> possible for client code to subclass it, which might make it more flexible.
I'm not convinced by the changes to Value - its there for storing arbitrary
values, rather than extending Value itself. It's probably worth noting
that .clone has changed in my version to this:
def clone(self):
return Value(self.version,
copy.deepcopy(self.value),self.store,self.key)
Which includes deepcopy on the value stored by Value. I'm beginning to think
that Value should be called "Variable" to make this clearer...
> Here is my suggestion, bare in mind that I have not tested the thread
> locking code beyond making sure that it runs :-)
The feedback is much appreciated - it's making me think more about the read
locking aspect. I suspect the GIL in CPython *may* make the reads safe, but
the lack of a GIL in jython & ironpython probably renders the reads in using &
get unsafe. (and I would like this to be safe in jython & ironpython)
It's interesting though, after having developed large amounts of code of code
based on no-shared-data & read-only/write-only pipes with data handoff and
not having had any major concurrency issues (despite mixing threads and non
threads) switching to a shared data model instantly causes problems.
The difference is really stark. One is simple, natural and easy and the other
is subtle & problematic. I'm not shocked, but find it amusing :-)
Many thanks for the feedback!
Michael.
More information about the python-uk
mailing list