How to read and write lock with Python?

Started

Multi-threading model provided by Python does not provide read-write locks, read and write mutex lock for simple, high applicability, can occupy multiple threads simultaneously read-write lock mode, but only one thread occupy write read-write lock mode.

Popular point that when there is no write lock, you can add any thread and read locks can be added at the same time; and a write lock only one thread, and when there is no need to add a read lock.

Simple implementation

import threadingclass RWlock(object):    def __init__(self):        self._lock = threading.Lock()        self._extra = threading.Lock()        self.read_num = 0    def read_acquire(self):        with self._extra:            self.read_num += 1            if self.read_num == 1:                self._lock.acquire()    def read_release(self):        with self._extra:            self.read_num -= 1            if self.read_num == 0:                self._lock.release()    def write_acquire(self):        self._lock.acquire()    def write_release(self):        self._lock.release()

This is a simple to read and write locks, self.read_num used to hold the number of threads to obtain a read lock, this property belongs to the critical zone, its operation should be locked, so there is a need for additional data protection inside the lock  self._extra .

But this lock is not fair. Ideally, the opportunity to obtain the thread should be the same regardless of the thread is a read or write operation. And you can see from the above code, the read request will be set up immediately  self.read_num += 1, whether or not to acquire the lock, and want to get a lock write requests have to wait  read_numto zero.

So this would only cause the lock is not occupied or not the read request, you can get write permissions. We should think of ways to avoid reading mode lock long-term occupation.

Read-write lock priority

Write lock took part in reading and writing priority priority. The above code belongs to the read priority.

If you want to change the priority to write, write it into threads to record the reference count, read and write at the same time competition, allowing the writer thread count increased to write, it will give the reader thread can not get a read lock has been since judge read the thread first written reference count is not 0, then wait for it to 0, and then read. This part of the code is not listed.

But this is clearly not flexible enough. We do not need to read and write two similar locks. We want to reconstruct our code to make it more powerful.

Improve

In order to meet custom priority read-write locks, read the number of threads waiting to be recorded, and requires two conditions threading.Condition to which party notification processing priority. Count references can expand semantics: positive: indicates the number of threads being read, a negative: that the number of threads are writing operation (up to -1)

When acquiring a read operation, to then determine when write waiting threads, no read operation is performed, there count read wait after adding a waiting  Condition notification; waiting to read count by 1, the count referenced by 1, to continue reading If the condition is not satisfied, circular wait;

When acquiring a write operation, if the lock is not occupied, the reference count is decremented, if the occupied, plus a number of threads waiting for a write, write condition waiting  Condition notification.

Read mode and write mode are the same release, it is necessary to inform the corresponding according to the judgment  Condition:

class RWLock(object):    def __init__(self):        self.lock = threading.Lock()        self.rcond = threading.Condition(self.lock)        self.wcond = threading.Condition(self.lock)        self.read_waiter = 0    # 等待获取读锁的线程数        self.write_waiter = 0   # 等待获取写锁的线程数        self.state = 0          # 正数:表示正在读操作的线程数   负数:表示正在写操作的线程数(最多-1)        self.owners = []        # 正在操作的线程id集合        self.write_first = True # 默认写优先,False表示读优先    def write_acquire(self, blocking=True):        # 获取写锁只有当        me = threading.get_ident()        with self.lock:            while not self._write_acquire(me):                if not blocking:                    return False                self.write_waiter += 1                self.wcond.wait()                self.write_waiter -= 1        return True    def _write_acquire(self, me):        # 获取写锁只有当锁没人占用,或者当前线程已经占用        if self.state == 0 or (self.state < 0 and me in self.owners):            self.state -= 1            self.owners.append(me)            return True        if self.state > 0 and me in self.owners:            raise RuntimeError("cannot recursively wrlock a rdlocked lock")        return False    def read_acquire(self, blocking=True):        me = threading.get_ident()        with self.lock:            while not self._read_acquire(me):                if not blocking:                    return False                self.read_waiter += 1                self.rcond.wait()                self.read_waiter -= 1        return True    def _read_acquire(self, me):        if self.state < 0:            # 如果锁被写锁占用            return False        if not self.write_waiter:            ok = True        else:            ok = me in self.owners        if ok or not self.write_first:            self.state += 1            self.owners.append(me)            return True        return False    def unlock(self):        me = threading.get_ident()        with self.lock:            try:                self.owners.remove(me)            except ValueError:                raise RuntimeError("cannot release un-acquired lock")            if self.state > 0:                self.state -= 1            else:                self.state += 1            if not self.state:                if self.write_waiter and self.write_first:   # 如果有写操作在等待(默认写优先)                    self.wcond.notify()                elif self.read_waiter:                    self.rcond.notify_all()                elif self.write_waiter:                    self.wcond.notify()    read_release = unlock    write_release = unlock

Product is slightly Library http://www.pinlue.com/

 

 

Guess you like

Origin blog.csdn.net/yihuliunian/article/details/91045543