Skip to content

Instantly share code, notes, and snippets.

@tylerneylon
Last active May 2, 2024 12:46
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save tylerneylon/a7ff6017b7a1f9a506cf75aa23eacfd6 to your computer and use it in GitHub Desktop.
Save tylerneylon/a7ff6017b7a1f9a506cf75aa23eacfd6 to your computer and use it in GitHub Desktop.
A simple read-write lock implementation in Python.
# -*- coding: utf-8 -*-
""" rwlock.py
A class to implement read-write locks on top of the standard threading
library.
This is implemented with two mutexes (threading.Lock instances) as per this
wikipedia pseudocode:
https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Using_two_mutexes
Code written by Tyler Neylon at Unbox Research.
This file is public domain.
"""
# _______________________________________________________________________
# Imports
from contextlib import contextmanager
from threading import Lock
# _______________________________________________________________________
# Class
class RWLock(object):
""" RWLock class; this is meant to allow an object to be read from by
multiple threads, but only written to by a single thread at a time. See:
https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
Usage:
from rwlock import RWLock
my_obj_rwlock = RWLock()
# When reading from my_obj:
with my_obj_rwlock.r_locked():
do_read_only_things_with(my_obj)
# When writing to my_obj:
with my_obj_rwlock.w_locked():
mutate(my_obj)
"""
def __init__(self):
self.w_lock = Lock()
self.num_r_lock = Lock()
self.num_r = 0
# ___________________________________________________________________
# Reading methods.
def r_acquire(self):
self.num_r_lock.acquire()
self.num_r += 1
if self.num_r == 1:
self.w_lock.acquire()
self.num_r_lock.release()
def r_release(self):
assert self.num_r > 0
self.num_r_lock.acquire()
self.num_r -= 1
if self.num_r == 0:
self.w_lock.release()
self.num_r_lock.release()
@contextmanager
def r_locked(self):
""" This method is designed to be used via the `with` statement. """
try:
self.r_acquire()
yield
finally:
self.r_release()
# ___________________________________________________________________
# Writing methods.
def w_acquire(self):
self.w_lock.acquire()
def w_release(self):
self.w_lock.release()
@contextmanager
def w_locked(self):
""" This method is designed to be used via the `with` statement. """
try:
self.w_acquire()
yield
finally:
self.w_release()
@littlefattiger
Copy link

use time.sleep(1) to give them a chance to gain the lock

import threading
import time
# from rwlock import RWLock
marker = RWLock()

WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
today = 0

def calendar_reader(id_number):
    global today
    name = 'Reader-' + str(id_number)
    while today < len(WEEKDAYS)-1:
        # print(today)
        with marker.r_locked():
            print(name, 'sees that today is', WEEKDAYS[today])
        time.sleep(1)

def calendar_writer(id_number):
    
    global today
    name = 'Writer-' + str(id_number)
    while today < len(WEEKDAYS)-1:
        with marker.w_locked():
            today = (today + 1) % 7
            print(name, 'updated date to ', WEEKDAYS[today])
        time.sleep(1)
        

if __name__ == '__main__':
    for i in range(10):
        threading.Thread(target=calendar_reader, args=(i,)).start()
    for i in range(2):
        threading.Thread(target=calendar_writer, args=(i,)).start()

result:

Reader-0 sees that today is Sunday
Reader-1 sees that today is Sunday
Reader-2 sees that today is Sunday
Reader-3 sees that today is Sunday
Reader-4 sees that today is Sunday
Reader-5 sees that today is Sunday
Reader-6 sees that today is Sunday
Reader-7 sees that today is Sunday
Reader-8 sees that today is Sunday
Reader-9 sees that today is Sunday
Writer-0 updated date to  Monday
Writer-1 updated date to  Tuesday
Reader-4 sees that today is Tuesday
Reader-6 sees that today is Tuesday
Reader-0 sees that today is Tuesday
Reader-7 sees that today is Tuesday
Reader-3 sees that today is Tuesday
Reader-5 sees that today is Tuesday
Reader-2 sees that today is Tuesday
Reader-8 sees that today is Tuesday
Reader-1 sees that today is Tuesday
Reader-9 sees that today is Tuesday
Writer-0 updated date to  Wednesday
Writer-1 updated date to  Thursday
Reader-9 sees that today is Thursday
Reader-4 sees that today is Thursday
Reader-2 sees that today is Thursday
Reader-7 sees that today is Thursday
Reader-1 sees that today is Thursday
Reader-0 sees that today is Thursday
Reader-5 sees that today is Thursday
Reader-6 sees that today is Thursday
Reader-3 sees that today is Thursday
Reader-8 sees that today is Thursday
Writer-1 updated date to  Friday
Writer-0 updated date to  Saturday

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment