Synchronization lock Lock Rlock Semaphore Event Conditio in python multithreading

Abstract: In the application of multi-threading, how to ensure thread safety, synchronization between threads, or access to shared variables is a very difficult problem, and it is also a problem faced when using multi-threading. For more serious consequences, use the LockRlockSemaphoreEventCondition provided in python multithreading to ensure synchronization between threads, the latter guarantees the mutual exclusion problem of accessing shared variables. Object: An enhanced version of the Lock mutex, which can be owned by multiple threads at the same time, while Lock can only be owned by a thread at the same time

 

In the application of multi-threading, how to ensure thread safety, synchronization between threads, or access to shared variables is a very difficult problem, and it is also a problem faced when using multi-threading. If it is not handled properly, it will bring more problems Serious consequences, use the Lock Rlock Semaphore Event Condition provided in python multithreading to ensure synchronization between threads, which guarantees the mutual exclusion of access to shared variables

Lock &; RLock: Mutex is used to ensure that multiple threads access shared variables.
Semaphore object: An enhanced version of Lock mutex, which can be owned by multiple threads at the same time, while Lock can only be owned by one thread at the same time.
Event object: It is a way of communication between threads, which is equivalent to a signal. A thread can send a signal to another thread and let it perform an operation.
Condition object: it can process data after certain events are triggered or certain conditions are met

 

1. Lock (mutual exclusion lock)

Request Lock - Enter Lock Pool Wait - Acquire Lock - Locked - Release Lock
Lock (instruction lock) is the lowest level synchronization instruction available. When Lock is in the locked state, it is not owned by a specific thread. Lock contains two states - locked and unlocked, and two basic methods.
It can be considered that Lock has a lock pool. When a thread requests a lock, the thread is placed in the pool until the lock is obtained. Threads in the pool are in a synchronously blocked state in the statechart.
Constructor:
Lock()
Instance method:
acquire([timeout]): Puts the thread into a synchronous blocking state and tries to acquire the lock.
release(): Release the lock. The thread must have acquired the lock before use, otherwise an exception will be thrown.

if mutex.acquire(): counter += 1 print

if mutex.acquire():
    counter += 1
    print( "I am %s, set counter:%s" % (self.name, counter)
    mutex.release()

  

2. RLock (reentrant lock)

RLock (reentrant lock) is a synchronous instruction that can be requested multiple times by the same thread. RLock uses the concepts of "owned thread" and "recursion level". When locked, RLock is owned by a thread. The thread that owns the RLock can call acquire() again, and it needs to call release() the same number of times when releasing the lock.
It can be considered that RLock contains a lock pool and a counter with an initial value of 0. Each time acquire()/release() is successfully called, the counter will be +1/-1, and the lock will be unlocked when it is 0.
Constructor:
RLock()
Instance method:
acquire([timeout])/release(): Similar to Lock.

 

3. Semaphore (Shared Object Access)

Let’s talk about Semaphore again. To be honest, Semaphore is the latest synchronization lock I use. I used Rlock to implement a similar implementation in the past. . .

Semaphore manages a built-in counter,
the built-in counter is -1 whenever acquire() is
called; the built-in counter is +1 when release() is called;
the counter cannot be less than 0; when the counter is 0, acquire() will block the thread until other threads call release().

Going directly to the code, we control the semaphore to 3, that is to say, there are 3 threads that can use this lock at the same time, and the remaining threads can only block and wait...

#coding:utf-8
import time
import threading
semaphore = threading.Semaphore(3)
def func():
    if semaphore.acquire():
        for i in range(3):
              time.sleep(1)
              print (threading.currentThread().getName() + 'acquire lock')
              semaphore.release()
              print (threading.currentThread().getName() + 'release lock')
 
for i in range(5): t1 = threading.Thread(target=func) t1.start()

 

4. Event (inter-thread communication)

Event contains a flag bit, which is initially false.
You can use set() to set it to true;
or use clear() to reset it to false;
you can use is_set() to check the status of the flag bit; the
other most important function is wait(timeout=None) , used to block the current thread until the event's internal flag is set to true or the timeout times out. If the internal flag is true, the wait() function understands the return.

import threading
import time
class MyThread(threading.Thread):
  def __init__(self, signal):
    threading.Thread.__init__(self)
    self.singal = signal
  def run(self):     print("I am %s,I will sleep ..."%self.name )     self.singal.wait()     print("I am %s, I awake..." %self.name)

if __name__ == "__main__":   singal = threading.Event()   for t in range(0, 3):     thread = MyThread(singal)     thread.start()   print ("main thread sleep 3 seconds... " )   time.sleep(3)   singal.set()

 

5. Condition (thread synchronization)

Condition can be understood as an advanced trivial, which provides more advanced functions than Lock and RLock, allowing us to control complex thread synchronization issues. threadiong.Condition internally maintains a trivial object (the default is RLock), which can be passed in as a parameter when creating a Condigtion object. Condition also provides acquire and release methods, which have the same meaning as the trivial acquire and release methods. In fact, it simply calls the corresponding method of the internal trivial object. Condition also provides the following methods (special attention: these methods can only be called after acquiring, otherwise a RuntimeError exception will be reported.):

Condition.wait([timeout]):
The wait method releases the internal occupied chores, while the thread is suspended until it is woken up by a notification or times out (if the timeout parameter is provided). When the thread is awakened and re-occupied, the program will continue to execute.

Condition.notify():
Wake up a suspended thread (if there are suspended threads). Note: the notify() method will not release the occupied chores.

Condition.notify_all()
Condition.notifyAll()
wakes up all suspended threads (if there are suspended threads). Note: These methods do not release the occupied chores.

There is an example for Condition, you can watch it.

from threading import Thread, Condition
import time
import random
queue = []
MAX_NUM = 10
condition = Condition()
class ProducerThread(Thread):
  def run(self):
    nums = range(5)
    global queue
    while True:
      condition.acquire()
      if len(queue) == MAX_NUM:
        print ("Queue full, producer is waiting" )
        condition.wait()
        print ("Space in queue, Consumer notified the producer" )
      num = random.choice(nums)
      queue.append(num)
      print ("Produced", num)
      condition.notify()
      condition.release()
      time.sleep(random.random())

class ConsumerThread(Thread):
  def run(self):
    global queue
    while True:
      condition.acquire()
      if not queue:
        print ("Nothing in queue, consumer is waiting")
        condition.wait()
        print "Producer added something to queue and notified the consumer"
      num = queue.pop(0)
      print ("Consumed", num)
      condition.notify()
      condition.release()
      time.sleep(random.random())
ProducerThread().start()
ConsumerThread().start()

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325396503&siteId=291194637