16.2.4. Condition Objects
def Condition(*args, **kwargs):
"""Factory function that returns a new condition variable object.
A condition variable allows one or more threads to wait until they are
notified by another thread.
If the lock argument is given and not None, it must be a Lock or RLock
object, and it is used as the underlying lock. Otherwise, a new RLock object
is created and used as the underlying lock.
"""
A condition variable is always associated with some kind of lock; this can be passed in or one will be created by default. (Passing one in is useful when several condition variables must share the same lock.)
A condition variable has acquire() and release() methods that call the corresponding methods of the associated lock. It also has a wait() method, and notify() and notifyAll() methods. These three must only be called when the calling thread has acquired the lock, otherwise a RuntimeError is raised.
The wait() method releases the lock, and then blocks until it is awakened by a notify() or notifyAll() call for the same condition variable in another thread. Once awakened, it re-acquires the lock and returns. It is also possible to specify a timeout.
The notify() method wakes up one of the threads waiting for the condition variable, if any are waiting. The notifyAll() method wakes up all threads waiting for the condition variable.
Note: the notify() and notifyAll() methods don’t release the lock; this means that the thread or threads awakened will not return from their wait() call immediately, but only when the thread that called notify() or notifyAll() finally relinquishes ownership of the lock.
翻译:notify和notifyAll方法并没有释放锁,而是仅仅唤醒那些等待的线程,只有当调用notify和notifyAll的线程真正释放锁时(调用release方法),那些等待的线程才可以从wait方法中返回,进行往下执行。
Tip: the typical programming style using condition variables uses the lock to synchronize access to some shared state; threads that are interested in a particular change of state call wait() repeatedly until they see the desired state, while threads that modify the state call notify() or notifyAll() when they change the state in such a way that it could possibly be a desired state for one of the waiters. For example, the following code is a generic producer-consumer situation with unlimited buffer capacity:
# Consume one item
cv.acquire() #获取锁
while not an_item_is_available():
cv.wait() #释放锁,等待唤醒通知,然后获取锁
get_an_available_item()
cv.release() #释放锁
# Produce one item
cv.acquire() #获取锁
make_an_item_available()
cv.notify() #唤醒等待线程
cv.release() #释放锁
To choose between notify() and notifyAll(), consider whether one state change can be interesting for only one or several waiting threads. E.g. in a typical producer-consumer situation, adding one item to the buffer only needs to wake up one consumer thread.
用大白话说一下这个Condition的作用,以及有了Lock/RLock后,为什么还需要Condition.
- Lock/RLock是互斥锁,主要作用是并行访问共享资源时,保护共享资源,防止出现脏数据。
- Condition依赖于Lock/RLock,主要是使用了Lock/RLock的阻塞特性,同时Condition自身提供了wait/notify/notifyAll方法,用于通知其他并行线程,可以访问共享资源了。可以这么理解,Condition提供了一种多线程通信机制,线程1需要数据,那么线程1就阻塞等待,这是线程2就去制造数据,线程2制造好数据后,通知线程1可以去取数据了,然后线程1去获取数据。
演示:使用Condition实现生产者/消费者模型。
# coding:gbk
import threading
import time
cv=threading.Condition()
product=0
def an_item_is_available():
global product
if not product:
return False
else:
return True
def get_an_available_item():
global product
product-=1
return '消费了一个产品。。。\n'.decode('gbk')
def make_an_item_available():
global product
product+=1
return '生产了一个产品。。。\n'.decode('gbk')
def consume():
global cv
while True:
cv.acquire()
while not an_item_is_available():
cv.wait()
print get_an_available_item()
cv.release()
def produce():
global cv
while True:
cv.acquire()
print make_an_item_available()
cv.notify()
cv.release()
time.sleep(1)
if __name__ == '__main__':
t1=threading.Thread(target=produce,args=())
t2=threading.Thread(target=consume,args=())
t2.start()
time.sleep(10)
t1.start()
运行结果:
C:\Python27\python.exe E:/pythonproj/基础练习/t6.py
生产了一个产品。。。
消费了一个产品。。。
生产了一个产品。。。
消费了一个产品。。。
Process finished with exit code 1