代码:

# -*- 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:\Programs\Anaconda\python.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

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则不会的例子也就好解释了

个人理解:

[b0034] python 归纳 (十九)_线程同步_条件变量的更多相关文章

  1. Linux线程同步:条件变量

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

  2. 线程同步,条件变量pthread_cond_wait

    与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享的全局变量进行同步的一种机制,主 ...

  3. 四十二、Linux 线程——线程同步之条件变量之线程状态转换

    42.1 线程状态转换 42.1.1 状态转换图 42.1.2 一个线程计算,多个线程获取的案例 #include <stdio.h> #include <stdlib.h> ...

  4. UNIX环境高级编程——线程同步之条件变量以及属性

    条件变量变量也是出自POSIX线程标准,另一种线程同步机制.主要用来等待某个条件的发生.可以用来同步同一进程中的各个线程.当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变量来 ...

  5. linux线程同步(2)-条件变量

    一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...

  6. 四十一、Linux 线程——线程同步之条件变量

    41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...

  7. [b0031] python 归纳 (十六)_线程同步_锁

    # -*- coding: utf-8 -*- """ 学习 多线程同步 使用锁 threading.Lock() 逻辑: 2 个线程,操作同一个整型变量,一个加法,另外 ...

  8. [b0032] python 归纳 (十七)_线程同步_信号量Semaphore

    代码: # -*- coding: utf-8 -*- """ 多线程并发同步 ,使用信号量threading.Semaphore 逻辑: 多个线程,对同一个共享变量 , ...

  9. Python并行编程(六):线程同步之条件

    1.基本概念 条件指的是应用程序状态的改变.其中某些线程在等待某一条件发生,其 他线程会在该条件发生的时候进行通知,一旦条件发生,线程会拿到共享资源的唯一权限. 2.示例代码 from threadi ...

随机推荐

  1. OpenCV绘制直线,矩形和园

    首先导入我们所需要的库: import numpy as np import cv2 import matplotlib.pyplot as plt 自定义显示图像的函数: def show(imag ...

  2. iOSMultipeerConnectivity使用

    MultipeerConnectivity是iOS7推出的多点连接框架,多用于文件传输,类似于iOS设备的airTrop隔空投放,在没有联网的情况下也能聊天传文件. 使用方法,一个设备作为广播开放Pe ...

  3. echarts玩转图表之矩形树图

    前言 这是第一次用makedown编辑器写文章,感觉像一件利器,排版美观而且效率飙升.进入正题 Echart官网文档地址 针对于矩形树图api配置项链接 1. 完全从数据定义图形 $.get( &qu ...

  4. QT--HTTP图片下载器

    QT--HTTP图片下载器 1.http使用前提 QT       += core gui network    //必须加上network 2.必须头文件 #include <QNetwork ...

  5. springboot进入html

    话不多说,转载 https://blog.csdn.net/sinat_33889619/article/details/78339042 这个博客写的真好

  6. Android项目模块化/组件化开发(非原创)

    文章大纲 一.项目模块化初步介绍二.项目模块化的两种模式与比较三.大型项目模块化的演进四.项目模块化总结五.参考文章   一.项目模块化初步介绍 1. 前言 在Android开发中,随着项目的不断扩展 ...

  7. JS&Jquery基础之窗口对象的关系总结

    1.top    该变更永远指分割窗口最高层次的浏览器窗口.如果计划从分割窗口的最高层次开始执行命令,就可以用top变量.2.opener opener用于在window.open的页面引用执行该wi ...

  8. numpy和matplotlib的pyplot函数的简单应用实现

  9. Django celery 使用

    0.安装包 cachetools 3.1.1 celery 3.1.26.post2 celery-with-redis 3.0 certifi 2019.9.11 Django 2.2.6 djan ...

  10. AcWing 795. 前缀和

    题目地址  https://www.acwing.com/solution/AcWing/content/2075/ 题目描述输入一个长度为n的整数序列. 接下来再输入m个询问,每个询问输入一对l, ...