How to go about. On read/write locks

Piet van Oostrum piet at cs.uu.nl
Mon Apr 6 13:44:37 CEST 2009


>>>>> "Emanuele D'Arrigo" <manu3d at gmail.com> (ED) wrote:

>ED> Hi everybody,
>ED> I'm having a threading-related design issue and I suspect it has a
>ED> name that I just don't know.  Here's a description.

>ED> Let's assume a resource (i.e. a dictionary) that needs to be accessed
>ED> by multiple threads. A simple lock will do the job but in some
>ED> circumstances it will create an unnecessary bottleneck. I.e. let's
>ED> assume that most threads only need to have a -read- access to the
>ED> resource, while only few threads actually change the dictionary.
>ED> Ideally, the reading threads should not block each other. However, as
>ED> soon as a threads intends to change the dictionary it should let all
>ED> the reading threads finish, lock the access to the resource, change
>ED> it, and then release the lock.

>ED> I don't think it'd be difficult to implement but I'm wondering if
>ED> something in this direction has been done already, if it has a name or
>ED> if it's even well known design pattern.

>ED> Anybody can shed some light?

This is a classical synchronization problem with a classical solution: 
You treat the readers as a group, and the writers individually. So you
have a write lock that each writer has to acquire and release, but it is
acquired only by the first reader and released by the last one.
Therefore you need a counter of the number of readers, and manipulations
of this counter must be protected by another lock.

#------------------------------------------------------------------------
from threading import Lock

mutex = Lock()
writelock = Lock()
numreaders = 0
#------------------------------------------------------------------------
# Reader code:

mutex.acquire()
numreaders += 1
if numreaders == 1:
    writelock.acquire()
mutex.release()

## critical section for reader

mutex.acquire()
numreaders -= 1
if numreaders == 0:
    writelock.release()
mutex.release()
#------------------------------------------------------------------------
# Writer code:

writelock.acquire()

## critical section for writer

writer.release
#------------------------------------------------------------------------

Notes:
1. From Python 2.6 on you can use the with statement, which makes it
   more robust against exceptions:
with mutex:
    numreaders += 1
    if numreaders == 1:
        writelock.acquire()
etc.
In Python 2.5 you can also use this if you use:
from __future__ import with_statement

2. The code above can cause starvation for writers if there are many
   readers (or if new readers come in before all other readers have
   finished. You need at least one more lock and probably a writer
   counter to solve this.

3. See also http://code.activestate.com/recipes/465156/

4. The code has not been tested, not even for syntax errors.

-- 
Piet van Oostrum <piet at cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: piet at vanoostrum.org



More information about the Python-list mailing list