Hi,

Just posted this to comp.lang.python - but posting here as well :-) I've 
received some great feedback since the initial beta release of the 
minimalistic STM code I discussed and released 2 weeks ago. I've incorporated 
the feedback, and created a couple of examples based on the canonical dining 
philosophers example. (One based on normal python threads, one based on 
Kamaelia)

It turns out that there was a potential race hazard during "using" 
and "usevar" which I'd missed - many thanks to Richard Taylor for pointing 
out this issue.

Why is this relevant to Backstage?
==================================
It's part of the Kamaelia project - a project started (by me :) at BBC
Research - which has the long term goal of making concurrency simple and easy
to work with. IMO it's very close now to achieving that goal with the
incorporation of STM and nascent trivial multicore support. (latter: 
http://tinyurl.com/2o7evf )

Quite literally it's relevant due to backstage motto of "Use our stuff to 
build your stuff" :-)

This STM code is usable (and useful) outside Kamaelia as well as inside.

Changelog
=========
1.0.1

    * Improved locking. (fixed race hazards during copying for reading - the
       last release was noted as probably OK for CPython, but maybe not for
       Jython or IronPython. This version is more robust)
    * Added Dining Philosophers examples (threading & Axon threading)

Getting it
==========
You can download this release version here:

    * http://thwackety.com/Axon.STM-1.0.1.tar.gz 

(this will shift over to sourceforge, but probably after christmas)

Installing it
=============
    tar zxf Axon.STM-1.0.1.tar.gz
    cd Axon.STM-1.0.1/
    sudo python setup.py install

What IS it?, Why is it useful?, Docs? Using it?
===============================================
See website: http://kamaelia.sourceforge.net/STM

The short version is it makes dealing with shared data between threads (and
similar) safe. Specifically it's (from my perspective) mainly useful for
co-ordinating access to shared resources.

Dining Philosophers?
====================
See also:
http://yeoldeclue.com/cgi-bin/blog/blog.cgi?rm=viewpost&nodeid=1198452999

#!/usr/bin/python

# First some imports...

import random
import time
import Axon
from Axon.STM import Store

# And a single support function to make code clearer :-)

def all(aList, value):
    for i in aList:
        if value != i:
            return False
    return True

# We can then define a dining philosopher as follows:

class Philosopher(Axon.ThreadedComponent.threadedcomponent):
    forks = ["fork.1", "fork.2"] # default for testing :-)
    def main(self):
        while 1:
            X = self.getforks()
            time.sleep(0.2)
            self.releaseforks(X)
            time.sleep(0.3+random.random())

    def getforks(self):
        """
        Essentially what this says is:
           * I have a number of forks I'm expected to try and pick up.
           * So I grab a copy of the global state.
           * Check to see they're not owned by anyone:
              X[fork].value == None
           * If they're not, then setting their owner to "me":
               X[fork].value = self.name
           * Then try to commit that change of ownership
        """
        gotforks = False
        while not gotforks:
            try:
                X = self.store.using(*self.forks)
                if all([ X[fork].value for fork in self.forks], None):
                    for fork in self.forks:
                        X[fork].value = self.name
                    X.commit()
                    gotforks = True
                else:
                    time.sleep(random.random())
            except Axon.STM.ConcurrentUpdate:
                time.sleep(random.random())
        print "Got forks!", self.name, self.forks
        return X

    def releaseforks(self,X):
        """
        If that works, then I have the forks, otherwise I sleep and retry.
        I then later release the forks by setting their values to None and
        committing back.
        """
        print "releasing forks", self.name
        for fork in self.forks:
            X[fork].value = None
        X.commit()

# The final bit of the code simply sets the system in motion:
S = Store()
N = 5
for i in range(1,N):
    Philosopher(store=S,forks=["fork.%d" % i ,"fork.%d" % (i+1)]).activate()

Philosopher(store=S,forks=["fork.%d" % N ,"fork.%d" % 1]).run()

Thanks for this release
=======================
Many thanks go to Richard Taylor for detailed feedback and discussion 
regarding locking and for pointing me at MASCOT which made me think of doing 
the dining philosophers this way :-)

Future
======
This will be merged onto the mainline of Kamaelia (probably after christmas)
with some auxillary functions , as another feather aimed at making concurrency
easy to work with :-) Note: For the moment to use this alongside Kamaelia you
install this, then reinstall Axon over the top.

Merry Christmas,


Michael
--
http://kamaelia.sourceforge.net/Developers/
http://yeoldeclue.com/blog

-
Sent via the backstage.bbc.co.uk developer discussion group.  To unsubscribe, 
please send an email to [EMAIL PROTECTED] with  unsubscribe backstage-developer 
[your email] as the message.

Reply via email to