[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:\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 归纳 (十九)_线程同步_条件变量的更多相关文章
- Linux线程同步:条件变量
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
- 线程同步,条件变量pthread_cond_wait
与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享的全局变量进行同步的一种机制,主 ...
- 四十二、Linux 线程——线程同步之条件变量之线程状态转换
42.1 线程状态转换 42.1.1 状态转换图 42.1.2 一个线程计算,多个线程获取的案例 #include <stdio.h> #include <stdlib.h> ...
- UNIX环境高级编程——线程同步之条件变量以及属性
条件变量变量也是出自POSIX线程标准,另一种线程同步机制.主要用来等待某个条件的发生.可以用来同步同一进程中的各个线程.当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变量来 ...
- linux线程同步(2)-条件变量
一.概述 上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...
- 四十一、Linux 线程——线程同步之条件变量
41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...
- [b0031] python 归纳 (十六)_线程同步_锁
# -*- coding: utf-8 -*- """ 学习 多线程同步 使用锁 threading.Lock() 逻辑: 2 个线程,操作同一个整型变量,一个加法,另外 ...
- [b0032] python 归纳 (十七)_线程同步_信号量Semaphore
代码: # -*- coding: utf-8 -*- """ 多线程并发同步 ,使用信号量threading.Semaphore 逻辑: 多个线程,对同一个共享变量 , ...
- Python并行编程(六):线程同步之条件
1.基本概念 条件指的是应用程序状态的改变.其中某些线程在等待某一条件发生,其 他线程会在该条件发生的时候进行通知,一旦条件发生,线程会拿到共享资源的唯一权限. 2.示例代码 from threadi ...
随机推荐
- vue-cli 项目启动过程分析
启动时没有加入路由 先npm run dev 把项目启动起来.看到 这个熟悉的界面. 首先看到: 这是项目的入口文件,一般引用其他的js,也都是在这个文件进行引用的. 渲染的时候,就是对这个id=&q ...
- Android Gradle 学习笔记(三):Gradle 日志
在第一节,我们使用到了gradle -q hello命令行来运行Hello World,并对Hello World进行了简单的分析,了解到 gradle -q hello 的意思是要执行的build. ...
- Android框架式编程之EventBus
一.EventBus 简介 EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,Gihub地址是:EventBus. 它简化了应用程序内各个组件之间进行通信的复杂 ...
- opencv-python 图像处理(五)
Canny边缘检测 1) 使用高斯滤波器,以平滑图像,滤除噪声. 2) 计算图像中每个像素点的梯度强度和方向. 3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测 ...
- 详解 DNS 与 CoreDNS 的实现原理
域名系统(Domain Name System)是整个互联网的电话簿,它能够将可被人理解的域名翻译成可被机器理解 IP 地址,使得互联网的使用者不再需要直接接触很难阅读和理解的 IP 地址. http ...
- Automatic Tuning of Undo Retention 常见问题 (Doc ID 1579779.1)
Automatic Tuning of Undo Retention Common Issues (Doc ID 1579779.1) APPLIES TO: Oracle Database - En ...
- Linux-3.14.12内存管理笔记【构建内存管理框架(3)】
此处接前文,分析free_area_init_nodes()函数最后部分,分析其末尾的循环: for_each_online_node(nid) { pg_data_t *pgdat = NODE_D ...
- deepin,linux服务器,上传下载
------------恢复内容开始------------ 物理机:deepin系统15.11桌面版 服务器:centos7 一.ftp连接服务器 1. deepin默认没有安装命令行的ftp客户端 ...
- Java流程控制之选择语句
选择语句 选择语句也称之为判断语句,主要有2种写法,一种是if语句,一种是switch语句.下面我们就详细的介绍一下这2种语句的用法. 判断语句if if语句第一种形式: if 格式: 执行流程 首先 ...
- 设计模式-Facade(结构型模式) 针对 最终类的实现通过一系列类的相关操作,重点关注 起始与结尾的操作。
以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Facade.h #pragma once class Subsystem1 { public: Subsystem1() ...