代码:

# -*- 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. vue中使用router打开一个新的窗口

    一个单页应用打开一个新的窗口不是很好控制,比如权限的处理,因为原先的页面不会自动刷新,方法很简单: let routeData = this.$router.resolve({ name: " ...

  2. iOS----------如何给github的README添加图片

    1.在你的项目中建一个文件夹,专门存放图片.如果想简单操作的话,可以截个图直接拉到项目中. 2.将建好的文件夹上传到github进行同步 3.在github上找到图片的URL地址 4.按照如下格式   ...

  3. expect 知识与示例说明

    expect 知识与示例说明 2012/04/10 chenxin 2019/07/07 update Chenxin 参考 https://www.cnblogs.com/yinghao1991/p ...

  4. 子传父flase注意点

    1==>在子传递数据给父亲的时候, closeBottom(){ this.$emit("closeBottom",false) } false不加引号. 2==>

  5. JavaScript-----6.流程控制:分支

    1.流程控制 就是来控制代码按照何种顺序来执行,流程控制有三种结构:顺序结构.分支结构.循环结构 2.顺序流程控制 程序按照代码先后顺序依次执行 3.分支流程控制 JS中提供两种分支结构语句:if语句 ...

  6. MSYQL主从复制-Gtid方式

    目录 1.MYSQL主从复制-Gtid方式 1.环境准备 2.Master配置 3.Slave配置 4.报错&解决 我叫张贺,贪财好色.一名合格的LINUX运维工程师,专注于LINUX的学习和 ...

  7. QT debug执行exe文件 应用程序无法正常启动0xc000007b

    遇到这种错,发现并不是因为缺失dll文件,因为我把需要的DLL都放到Debug文件下了,但还是有这问题: 解决方法: 右键点击-- >我的电脑--属性-->高级系统设置-->环境变量 ...

  8. nodejs+Express中使用mustache模板引擎

    由于公司一个seo项目,需要我协助.此项目他人已经开发大半,由于seo需要,使用了服务器端模板引擎.我项目的后端同事说项目是go语音写的,跑项目麻烦,只给了我template和css等静态文件. 为了 ...

  9. 【Java】String的首尾去空和判空

    去除字符串首尾空白字符:包括\t,\r,\n及" ": //去除字符串首尾空白字符:包括\t,\r,\n及" ": System.out.println(&qu ...

  10. JavaWeb 增删改查功能

    1.今天来写一个简单的增删改查功能,这个项目还是接着在昨天写的 --JavaWeb实现简单登录注册-- 来写的. 登录成功进来后对学生信息的增删改查 2.项目文件为: 3.好了,直接贴上今天新写的代码 ...