zoukankan      html  css  js  c++  java
  • [b0034] python 归纳 (十九)_线程同步_条件变量

     代码:

    # -*- coding: utf-8 -*-
    """
    学习线程同步,使用条件变量
    逻辑:
         生产消费者模型
         一个有3个大小的产品库,一个生产者负责生产,一个消费者负责消费
         每次生产或消费一个产品,产品库满了,生产者必须等待,产品库空了,消费者必须等待
         生产者的速度是消费者的速度2倍,先启动消费者,一段时间后启动生产者
    
    总结:
        1. 条件变量底层用到R锁,对于已经获得锁的线程可以执行多次 acquire(),锁多次
        2. 不确定是否和java的这一套 ,原理一样
    
    使用:
        1. 创建条件对象  cond = threading.Condition()
        2. 在子线程调用 申请获取锁  cond.acquire()
        3. 在程序中如果有必要 使用 cond.wait()  cond.notify() cond.notifyall()
        4. 使用完后 释放锁 cond.release()
    
    参考:
    
    """
    import threading
    import time
    
    class Goods:
        """ 记录产品数,最多3个产品
            被多线程操作
        """
        def __init__(self):
            self.count = 0
    
        def add(self,num = 1):
            self.count += num
    
        def sub(self):
            if self.count>=0:
                self.count -= 1
    
        def empty(self):
            return self.count <= 0
    
        def full(self):
            return self.count >= 3
    
    
    class Producer(threading.Thread):
        """ 生产者
        """
        def __init__(self,condition,goods,name, sleeptime=1):
            threading.Thread.__init__(self)
            self.cond = condition
            self.goods = goods
            self.sleeptime = sleeptime
            self.name = name
    
        def run(self):
            cond = self.cond
            goods = self.goods
    
            while True:
                print "p1"
                cond.acquire() # 获取锁
                print "p2"
    
                while goods.full(): # 如果产品满了
                    print "p3"
                    cond.wait()
                    print  cond._Condition__lock
                    print "p4"
    
                print "p5"
                goods.add()
                print("num:",goods.count,"producer")
    
                cond.notifyAll()  # 唤醒所有等待的线程,并没有交出锁
                print  cond._Condition__lock # 锁还在
                print "p6"
    
                cond.release()    # 解锁资源
                print  cond._Condition__lock   # 锁不在了
                print "p7"
    
                time.sleep(self.sleeptime)
    
    
    class Consumer(threading.Thread):
        """ 消费者
        """
        def __init__(self,condition,goods,name, sleeptime=2):
            threading.Thread.__init__(self)
            self.cond = condition
            self.goods = goods
            self.sleeptime = sleeptime
            self.name = name
    
        def run(self):
            cond = self.cond
            goods = self.goods
    
            while True:
                print "c1"
                cond.acquire() # 获取锁
                print "c2"
    
                while goods.empty(): # 如果没有产品了
                    print "c3"
                    cond.wait()   #  执行它,交出锁,进入等待池,然后阻塞,直到被唤醒
                    print  cond._Condition__lock    #  执行到这里,继续获得了锁
                    print "c4"
    
                print "c5"
                goods.sub()
                print("num:",goods.count, "consumer")
    
                cond.notifyAll()  # 唤醒所有等待的线程,并没有交出锁
                print  cond._Condition__lock # 锁还在
                print "c6"
    
                cond.release()    #  解锁资源
                print  cond._Condition__lock   # 锁不在了
                print "c7"
    
                time.sleep(self.sleeptime)
    
    
    if __name__ == '__main__':
        g = Goods() # 共享数据
        cond = threading.Condition() # 条件判断
    
        # 启动消费者
        consumer = Consumer(cond,g, name="consumer")
        consumer.start()
    
        # 2秒后启动生产者
        time.sleep(2)
    
        print "m1"
    
        # 启动生产者
        producer = Producer(cond,g, name="producer")
        producer.start()
    
        print "m2"

    2 输出:

    D:ProgramsAnacondapython.exe D:/1_practice/python/projects/downloads_modify/归类/并发/thread_sync_5.py
    c1
    c2
    c3
    m1
    p1m2
    
    p2
    p5
    ('num:', 1, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0><_RLock owner='consumer' count=1>
    
    p7c4
    
    c5
    ('num:', 0, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0>
    c7
    p1
    p2
    p5
    ('num:', 1, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p5
    ('num:', 2, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    c1
    c2
    c5
    ('num:', 1, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0>
    c7
    p1
    p2
    p5
    ('num:', 2, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0>
    c7
    p1
    p2
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0><_RLock owner='producer' count=1>
    
    c7p4
    
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0><_RLock owner='producer' count=1>
    
    c7p4
    
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner='producer' count=1><_RLock owner=None count=1>
    
    p4c7
    
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0><_RLock owner='producer' count=1>
    
    c7p4
    
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0><_RLock owner='producer' count=1>
    
    c7p4
    
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0>
     c7<_RLock owner='producer' count=1>
    
    p4
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    p1
    p2
    p3
    c1
    c2
    c5
    ('num:', 2, 'consumer')
    <_RLock owner='consumer' count=1>
    c6
    <_RLock owner=None count=0><_RLock owner='producer' count=1>
    
    c7p4
    
    p5
    ('num:', 3, 'producer')
    <_RLock owner='producer' count=1>
    p6
    <_RLock owner=None count=0>
    p7
    
    Process finished with exit code -1
    View Code

    3 输出解读:

     4 相关资料

    java中的notify和notifyAll有什么区别?

    先说两个概念:锁池和等待池

    • 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
    • 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中
    Reference:java中的锁池和等待池

    链接:https://www.zhihu.com/question/37601861/answer/145545371

    然后再来说notify和notifyAll的区别

    • 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁
    • 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
    • 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
    Reference:线程间协作:wait、notify、notifyAll

    综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。

    有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了

    个人理解:

  • 相关阅读:
    洛谷—— P3353 在你窗外闪耀的星星
    洛谷—— P1238 走迷宫
    洛谷—— P1262 间谍网络
    9.8——模拟赛
    洛谷—— P1189 SEARCH
    算法
    May 22nd 2017 Week 21st Monday
    May 21st 2017 Week 21st Sunday
    May 20th 2017 Week 20th Saturday
    May 19th 2017 Week 20th Friday
  • 原文地址:https://www.cnblogs.com/sunzebo/p/9631900.html
Copyright © 2011-2022 走看看