Synchronization methodology

Paul Rubin http
Wed Jan 3 06:01:10 EST 2007


Chris Ashurst <chris at telestatic.net> writes:
> Hi, I'm coming in from a despised Java background, and I'm having some
> trouble wrapping my head around sharing an object between multiple
> instances of a single class (in simpler terms, I would say imagine a
> simple chat server that has to share a list of connected users to each
> instance of a connected user).

If you're doing this with threads, one common Pythonic style is
generally to have the threads communicate through queues (see docs for
the Queue module).  This is sort of a cheap version of the CSP
(communicating sequential processes) approach.  You might have a
service thread that takes care of those shared objects, reading
requests from a queue (untested):

   # All client threads write their requests to this queue, and
   # the service loop reads from it
   service_queue = Queue()

   # make one of these in each client thread
   class Request(Queue.Queue):
      def __call__(self, reply_queue, func, *args, **kwargs):
          service_queue.put((self, func, args, kwargs))
          return self.get()

   def service_loop():
     while True:
        client, func, args, kwargs = service_queue.get()
        client.put (func(*args, **kwargs))

   Threading.Thread(target=service_loop).start()

Then in your connected user thread you could say:

   # set up a reply queue for this user's thread
   request = Request()
   ...

   # add the user to the connected user list, with timestamp and remote IP
   status = request(user_list.append, self, time(), remote_ip=whatever)

The last line would drop a request on the service queue to perform the
function call

    user_list.append(time(), remote_ip=whatever)

The service queue thread would retrieve the request, call the
function, and pass the result back through the reply queue.  The idea
is you'd handle all operations on user_list in the service thread, so
access is completely serialized using the queues.  You can see that
you can easily construct any function call that then gets executed in
the other thread, without having to use a bunch of boilerplate at each
request.  You have to be a bit careful to not use long-running
requests that could block other threads from getting their requests
serviced.  Use additional threads if you need such requests.

You sometimes end up creating more threads than necessary this way but
you tend to not have many synchronization problems if you stick with
this style.



More information about the Python-list mailing list