threading模块之Condition

condition基本用法

cv = threading.Condition()
#消费者线程
cv.acquire()
while not available():
	cv.wait()
cv.release()

#生成者线程
cv.acquire()
make_available()
cv.notify()
cv.release()

wait和Notify分析

class Condition:
	def __init__(self, lock=None):
	        if lock is None:
	            lock = RLock()
	        self._lock = lock
	        # Export the lock's acquire() and release() methods
	        self.acquire = lock.acquire
	        self.release = lock.release
	        self._waiters = _deque()
	        
	def wait(self, timeout=None):
	        if not self._is_owned():
	            raise RuntimeError("cannot wait on un-acquired lock")
	        waiter = _allocate_lock()
	        waiter.acquire()
	        self._waiters.append(waiter)
	        saved_state = self._release_save()
	        gotit = False
	        try:    # restore state no matter what (e.g., KeyboardInterrupt)
	            if timeout is None:
	                waiter.acquire()
	                gotit = True
	            else:
	                if timeout > 0:
	                    gotit = waiter.acquire(True, timeout)
	                else:
	                    gotit = waiter.acquire(False)
	            return gotit
	        finally:
	            self._acquire_restore(saved_state)
	            if not gotit:
	                try:
	                    self._waiters.remove(waiter)
	                except ValueError:
	                    pass
	                    
	def notify(self, n=1):
        if not self._is_owned():
            raise RuntimeError("cannot notify on un-acquired lock")
        all_waiters = self._waiters
        waiters_to_notify = _deque(_islice(all_waiters, n))
        if not waiters_to_notify:
            return
        for waiter in waiters_to_notify:
            waiter.release()
            try:
                all_waiters.remove(waiter)
            except ValueError:
                pass

cv.acquire和cv.release()都是简单的调用上锁和解锁。
Python的Condition使用方式和pthread_cond_wait、QWaitCondition等一样,都需要集合锁使用,在wait之前先锁定,且必须是本线程锁定。
否则抛出异常raise RuntimeError(“cannot wait on un-acquired lock”)

为了使叙述简单,我们用
锁1表示Condition的内部锁 (互斥锁或者递归锁都行)
锁2表示waiter,肯定是互斥锁

wait线程分析:

  1. 锁1上锁
  2. 判断需要的资源是否已就绪,若OK就直接跳转到步骤8。否则开始wait(),等待资源,下面步骤3-步骤7都是wait中的代码流程。
  3. 创建锁2
  4. 锁2上锁
  5. 锁1解锁,让生成者线程能获取锁1
  6. 再次尝试对锁2上锁,因为是锁2是互斥锁且之前已经在步骤4上锁,所以必须等待别的线程对锁2解锁或者超时后才能范围,此时消费者线程挂起。------->等待生产者线程步骤2唤醒
  7. 再次对锁1重新上锁
  8. 根据准备就绪的资源处理业务。
  9. 锁1解锁,返回

如果未设置等待的超时时间,wait线程将会阻塞在步骤6,且锁1已处于解锁状态。notify线程将获取到锁1

notify线程分析:

  1. 尝试对锁1上锁,需要在wait步骤4才能成功,否则一直阻塞
  2. 给wait线程准备需要的资源
  3. 将锁2解锁,通知wait线程资源已就绪--------->唤醒wait线程
  4. 对锁1解锁--------->让wait线程能重新对锁1上锁

为何wait之前需要锁定?

分析问题我们可从反面分析,例如数学上的反证法。
假设wait线程之前未对锁1锁定,在wait线程步骤3时,资源此时就绪,notify线程发出通知,但是此时并没有任何wait线程在等待锁2解锁,待wait线程执行到步骤6时,就会一直等待下一次的notify而阻塞。

本文深入的分析了threading模块中condition条件变量的使用及其原理,对知识的认识做到知其然而知其所以然。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值