Objective record
1. Complex thread synchronization
1.1 Producer consumer issues
1.2 threading.Conditon The basic principle
2. threading.Condition
2.1 threading.Conditon Properties and methods
2.2 threading.Conditon Use demonstration
Python Multithreaded programming Directory
Python Multithreaded programming -01-threading The module first
Python Multithreaded programming -02-threading modular - Use of locks
The previous two chapters have already said threading Use of mutexes in modules , Whether it's threading.Lock still threading.RLock, This mutex is the simplest thread synchronization mechanism , In practice, there are many complex situations that cannot be solved by mutual exclusion . and Python Provided Condition Object provides support for complex thread synchronization problems .
The common producer consumer model is specifically , It's in a system , There are two roles of producer and consumer , They communicate through memory buffers , Producers produce the information consumers need , Data generated by consumer consumption , The size of the shared memory buffer pool between producers and consumers is variable , The number of producers is variable , The number of consumers is variable .
Questions like this , It is more difficult to solve the problem with a simple mutex .
Condition It's called a conditional variable , It can be understood as an advanced lock , The basic principles used are as follows :
1、Condition The constructor of an object can accept a Lock/RLock Object as parameter , If not specified , Default is Reentrant lock RLock, Generated Condition Object will maintain a Lock/RLock And a waiting pool .
2、 Thread calls acquire Methods to get Condition object , This and Lock/RLock similar .
# wait() Method 、notify() Method 、notifiy_all() Methods can only be called on threads acquire After method , Thread calls release Before method !
3、 Thread calls wait When the method is used , The thread will release Condition Lock inside and enter blocked state , At the same time waiting Record this thread in the pool .
4、 Thread calls notify/notify_all When the method is used ,Condition The object will come from waiting Pick a thread in the pool , Notify it to call acquire Method to try to get the lock . Threads can only pass through notify Method wake up , therefore notifyAll The function of is to prevent some threads from being silent forever .
5、 Thread calls release Methods to release Condition object
Condition It's called a conditional variable , In addition to providing with Lock、RLock Allied acquire() and release() Outside method , It also provides wait() 、notify()、notifyAll() Method .
acquire
(blocking=True)
Lock this Condidtion, Then it returns a Boolean value .
`blocking` Indicate this Condition When you can't lock , Whether the thread is blocked .
If `blocking` yes False And another thread has locked this Conditon, Then go back to False.
If `blocking` yes True And another thread has locked this Conditon, Then block the thread until Condition Be released , Get it and return True. The blocking process can be interrupted .
Other situations return immediately True. To be exact , If Current The thread has locked this Condition, Then add one to the built-in counter , If no thread locks this Condition, Get this lock , And the built-in counter is initialized to 1.
It means Conditon It's reentrant .
2release() Release this Condition, Allow other threads in the blocking wait queue to get this Condition. This Condition It must be locked at this moment , And is locked by the same thread , Otherwise return to RuntimeError.Wake up one or more people waiting for this Condition The thread of . If the awakened thread does not acquire This Condition, So what RuntimeError.
This method wakes up at most n individual Threads . If there are no threads waiting , There is no action .
4notifyAll() Wake up all who are waiting for this Condition The thread of . If the awakened thread does not lock this Condition, So what RuntimeError.5wait
(timeout=None)
Block and wait until Condition Release or timeout expire .
If the awakened thread does not acquire This Condition, So what RuntimeError.
This method releases the underlying lock , Then block until it is blocked by other threads notify() perhaps notify_all() Wake up the , Or until optional timeout expire . Once awakened or timeout expire , It will again acquire This lock , And back to .
timeout argument If it appears and is not None, It should be a floating-point number that specifies the operation timeout , In seconds
When the basic lock is RLock when , Will not use its release() Method , Because this may not actually unlock multiple recursive acquisitions when the lock is opened . Instead, an internal interface is used RLock Class is recursively obtained multiple times . Another internal interface is then used to restore the recursion level when the lock is reacquired .
6wait_for(predicate, timeout=None)Wait until the condition changes to True.predicate It should be a callable object , And the result is a Boolean value .timeout Used to give the longest waiting time .
The following code takes the producer - The consumer is an example , A resource pool can store at most 5 Items , A production thread can generate at most 5 Items , Consumers take one item at a time , If there is less than... In the resource pool 4 Items , Then remind the production thread to continue to generate items .
Please note that Producer Waiting code in self.con.wait(), Not used timeout, In this way, it will keep blocking and waiting .
and Consumer Waiting code in self.con.wait(6), wait until 6 Seconds later, the blocking waiting state will be automatically released , Please think about why .
import threading
import time
max_goods_num=10
min_goods_num=4
con = threading.Condition()
num = 0
class Producer(threading.Thread):
def __init__(self, con):
self.con = con
super().__init__()
def run(self):
global num
print("*"*50)
print("Coming in Producer ",time.ctime())
self.con.acquire()
for _ in range(max_goods_num):
print("---------- Enter the cycle item generation program ------------")
print(" Start generating items ")
num += 1
print(" The number of items in the resource pool is :{}".format(num))
time.sleep(1)
if num == 5:
print(" The number of items in the resource pool has reached five , Unable to continue generation ")
self.con.notify()
self.con.wait()
self.con.release()
print("Producer run exit")
class Consumer(threading.Thread):
def __init__(self, con):
self.con = con
super().__init__()
def run(self):
print("*"*50)
print("Coming in Consumer ",time.ctime())
self.con.acquire()
global num
while num:
print("---------- Enter the cycle consumable program ------------")
num -= 1
print(" There are still items left in the resource pool :{}".format(num))
time.sleep(0.5)
if num <min_goods_num :
print(" The number of items in the resource pool is less than min_goods_num, Need to add !")
self.con.notify()
self.con.wait(6)
self.con.release()
print("Consumer run exit")
p = Producer(con)
c = Consumer(con)
p.start()
c.start()
'''
If everyone thinks it's ok , Please order a praise or collection , Think of a blog to increase popularity , Thank you very much !
'''