Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a697058

Browse files
committed
Added optional lock parameter to condition class.
Added mrsw (multiple-reader-single-writer) lock.
1 parent c95f724 commit a697058

1 file changed

Lines changed: 114 additions & 7 deletions

File tree

Demo/threads/sync.py

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
# Defines classes that provide synchronization objects. Note that use of
22
# this module requires that your Python support threads.
33
#
4-
# condition() # a POSIX-like condition-variable object
5-
# barrier(n) # an n-thread barrier
6-
# event() # an event object
7-
# semaphore(n=1)# a semaphore object, with initial count n
4+
# condition(lock=None) # a POSIX-like condition-variable object
5+
# barrier(n) # an n-thread barrier
6+
# event() # an event object
7+
# semaphore(n=1) # a semaphore object, with initial count n
8+
# mrsw() # a multiple-reader single-writer lock
89
#
910
# CONDITIONS
1011
#
1112
# A condition object is created via
1213
# import this_module
13-
# your_condition_object = this_module.condition()
14+
# your_condition_object = this_module.condition(lock=None)
15+
#
16+
# As explained below, a condition object has a lock associated with it,
17+
# used in the protocol to protect condition data. You can specify a
18+
# lock to use in the constructor, else the constructor will allocate
19+
# an anonymous lock for you. Specifying a lock explicitly can be useful
20+
# when more than one condition keys off the same set of shared data.
1421
#
1522
# Methods:
1623
# .acquire()
@@ -209,13 +216,63 @@
209216
# any) blocked by a .p(). It's an (detected) error for a .v() to
210217
# increase the semaphore's count to a value larger than the initial
211218
# count.
219+
#
220+
# MULTIPLE-READER SINGLE-WRITER LOCKS
221+
#
222+
# A mrsw lock is created via
223+
# import this_module
224+
# your_mrsw_lock = this_module.mrsw()
225+
#
226+
# This kind of lock is often useful with complex shared data structures.
227+
# The object lets any number of "readers" proceed, so long as no thread
228+
# wishes to "write". When a (one or more) thread declares its intention
229+
# to "write" (e.g., to update a shared structure), all current readers
230+
# are allowed to finish, and then a writer gets exclusive access; all
231+
# other readers & writers are blocked until the current writer completes.
232+
# Finally, if some thread is waiting to write and another is waiting to
233+
# read, the writer takes precedence.
234+
#
235+
# Methods:
236+
#
237+
# .read_in()
238+
# If no thread is writing or waiting to write, returns immediately.
239+
# Else blocks until no thread is writing or waiting to write. So
240+
# long as some thread has completed a .read_in but not a .read_out,
241+
# writers are blocked.
242+
#
243+
# .read_out()
244+
# Use sometime after a .read_in to declare that the thread is done
245+
# reading. When all threads complete reading, a writer can proceed.
246+
#
247+
# .write_in()
248+
# If no thread is writing (has completed a .write_in, but hasn't yet
249+
# done a .write_out) or reading (similarly), returns immediately.
250+
# Else blocks the calling thread, and threads waiting to read, until
251+
# the current writer completes writing or all the current readers
252+
# complete reading; if then more than one thread is waiting to
253+
# write, one of them is allowed to proceed, but which one is not
254+
# specified.
255+
#
256+
# .write_out()
257+
# Use sometime after a .write_in to declare that the thread is done
258+
# writing. Then if some other thread is waiting to write, it's
259+
# allowed to proceed. Else all threads (if any) waiting to read are
260+
# allowed to proceed.
212261

213262
import thread
214263

215264
class condition:
216-
def __init__(self):
265+
def __init__(self, lock=None):
217266
# the lock actually used by .acquire() and .release()
218-
self.mutex = thread.allocate_lock()
267+
if lock is None:
268+
self.mutex = thread.allocate_lock()
269+
else:
270+
if hasattr(lock, 'acquire') and \
271+
hasattr(lock, 'release'):
272+
self.mutex = lock
273+
else:
274+
raise TypeError, 'condition constructor requires ' \
275+
'a lock argument'
219276

220277
# lock used to block threads until a signal
221278
self.checkout = thread.allocate_lock()
@@ -357,6 +414,56 @@ def v(self):
357414
self.nonzero.signal()
358415
self.nonzero.release()
359416

417+
class mrsw:
418+
def __init__(self):
419+
# critical-section lock & the data it protects
420+
self.rwOK = thread.allocate_lock()
421+
self.nr = 0 # number readers actively reading (not just waiting)
422+
self.nw = 0 # number writers either waiting to write or writing
423+
self.writing = 0 # 1 iff some thread is writing
424+
425+
# conditions
426+
self.readOK = condition(self.rwOK) # OK to unblock readers
427+
self.writeOK = condition(self.rwOK) # OK to unblock writers
428+
429+
def read_in(self):
430+
self.rwOK.acquire()
431+
while self.nw:
432+
self.readOK.wait()
433+
self.nr = self.nr + 1
434+
self.rwOK.release()
435+
436+
def read_out(self):
437+
self.rwOK.acquire()
438+
if self.nr <= 0:
439+
raise ValueError, \
440+
'.read_out() invoked without an active reader'
441+
self.nr = self.nr - 1
442+
if self.nr == 0:
443+
self.writeOK.signal()
444+
self.rwOK.release()
445+
446+
def write_in(self):
447+
self.rwOK.acquire()
448+
self.nw = self.nw + 1
449+
while self.writing or self.nr:
450+
self.writeOK.wait()
451+
self.writing = 1
452+
self.rwOK.release()
453+
454+
def write_out(self):
455+
self.rwOK.acquire()
456+
if not self.writing:
457+
raise ValueError, \
458+
'.write_out() invoked without an active writer'
459+
self.writing = 0
460+
self.nw = self.nw - 1
461+
if self.nw:
462+
self.writeOK.signal()
463+
else:
464+
self.readOK.broadcast()
465+
self.rwOK.release()
466+
360467
# The rest of the file is a test case, that runs a number of parallelized
361468
# quicksorts in parallel. If it works, you'll get about 600 lines of
362469
# tracing output, with a line like

0 commit comments

Comments
 (0)