python系列——多线程之条件变量condition

参考博客:

http://c.biancheng.net/view/2622.html   (存钱取钱)

https://www.cnblogs.com/yoyoketang/p/8337118.html  (用于生产者消费者)

https://www.cnblogs.com/franknihao/p/6627857.html  (捉迷藏例子详细解释了condition的作用过程)

为什么要用condition:

当线程在系统中运行时,线程的调度具有一定的透明性,通常程序无法准确控制线程的轮换执行,如果有需要,Python 可通过线程通信来保证线程协调运行。

如何起作用:

假设系统中有两个线程,这两个线程分别代表存款者和取钱者,现在假设系统有一种特殊的要求,即要求存款者和取钱者不断地重复存款、取钱的动作,而且要求每当存款者将钱存入指定账户后,取钱者就立即取出该笔钱。不允许存款者连续两次存钱,也不允许取钱者连续两次取钱。

为了实现这种功能,可以借助于 Condition 对象来保持协调。使用 Condition 可以让那些己经得到 Lock 对象却无法继续执行的线程释放 Lock 对象,Condition 对象也可以唤醒其他处于等待状态的线程。

wait和release的区别:

release和wait都有释放锁的作用,不同在于wait后,该子线程就在那里挂起等待,要继续执行,就需要接收到notify或者notifyAll来唤醒线程,而release该线程还能继续执行。

wait会释放锁但是会挂起线程,不会继续向下运行。而release释放锁后有可能该线程继续向下运行。

阻塞和挂起的区别:

在说Condition之前还需要明确一下线程的几个概念。线程的阻塞和挂起,线程的这两个状态乍一看都是线程暂停不再继续往前运行,但是引起的原因不太一样。阻塞是指线程间互相的制约,当一个线程获得了锁,其他的线程就被阻塞了,而挂起是出于统一调度的考虑。换句话说,挂起是一种主动的行为,在程序中我们主动挂起某个线程然后可以主动放下让线程继续运行;而阻塞更多时候是被动发生的,当有线程操作冲突了那么必然是有一方要被阻塞的。从层级上看,挂起操作是高于阻塞的,也就说一个线程可以在阻塞的时候被挂起,然后被唤醒后依然是阻塞状态。如果在挂起过程中具备了运行条件(即不再阻塞),线程也不会往前运行。

捉迷藏具体例子:

import threading,time

class Seeker(threading.Thread):
    def __init__(self,cond,name):
        Thread.__init__(self)
        self.cond = cond
        self.name = name

    def run(self):
        time.sleep(1)    #1.确保seeker晚于hider开始执行

        self.cond.acquire()    #4. hider的锁释放了所以这里获得了锁
        print '我把眼睛蒙上了'
        self.cond.notify()    #5.蒙上眼后通知hider,hider线程此时被唤醒并试图获取锁,但是锁还在seeker身上,所以hider被阻塞,seeker继续往下
        self.cond.wait()  #6. seeker锁被释放并且挂起,hider就获取锁开始继续往下运行了
        
        print '我找到你了'
        self.cond.notify()  #9.找到了之后通知hider,hider意图获取锁但不行所以被阻塞,seeker往下
        self.cond.release()  #10.释放锁

        print '我赢了'

class Hider(threading.Thread):
        def __init__(self,cond,name):
            Thread.__init__(self)
            self.cond = cond
            self.name = name
        
        def run(self):
            self.cond.acquire()    #2.hider获取锁
            self.cond.wait()    #3.hider被挂起然后释放锁
            
            print '我已经藏好了'
            self.cond.notify()  #7.藏好后通知seeker,seeker意图获取锁,但是锁在hider身上所以seeker被阻塞
            self.cond.wait()    #8.hider被挂起,释放锁,seeker获取锁,seeker继续往下运行

            self.cond.release()  #11. 在此句之前一点,seeker释放了锁(#10),hider得到锁,随即这句hider释放锁
            print '被你找到了'

cond = threading.Condition()
seeker = Seeker(cond,'seeker')
hider = Hider(cond,'hider')
seeker.start()
hider.start()

'''
结果:
我把眼睛蒙上了
我已经藏好了
我找到你了
我赢了
被你找到了
'''

这里需要注意的是#10 self.cond.release方法不能省,否则会引起死锁。而#11 处的

self.cond.release() 可以被省略
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值