线程之死锁、递归锁、信号量、事件Event 、定时器
1.死锁的现象
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
# from threading import Thread, Lock
# import time
#
# # 互斥锁的死锁
# mutexA = Lock()
# mutexB = Lock()
#
#
# class Mythread(Thread):
# def run(self):
# self.f1()
# self.f2()
#
# def f1(self):
# mutexA.acquire()
# print("%s get the lock A" % self.name)
# mutexB.acquire()
# print("%s get the lock B" % self.name)
# mutexA.release()
# mutexB.release()
#
# def f2(self):
# mutexB.acquire()
# print("%s get the lock B" % self.name)
# time.sleep(0.2)
# mutexA.acquire()
# print("%s get the lock A" % self.name)
# mutexA.release()
# mutexB.release()
#
#
# if __name__ == '__main__': #死锁的现象出现是因为互斥锁只能acqurie一次不能多次,上面的实例说明:
# # 当线程2拿到A锁的时候去拿B锁这时候线程1还拿着B锁,导致线程2拿不到B锁,但是线程1 拿A锁的时候发现A锁在线程2
# # 手里拿不到,他也释放不了各自所拿的锁,就造成了死锁
# for i in range(10):
# t = Mythread()
# t.start()
res---->:
Thread-1 拿到A锁
Thread-1 拿到B锁
Thread-1 拿到B锁
Thread-2 拿到A锁 #出现死锁,整个程序阻塞住
2.递归锁
解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁,二者的区别是:递归锁可以连续acquire多次,而互斥锁只能acquire一次.
from threading import Thread, RLock
import time
# 递归锁
mutexA = mutexB = RLock() # 定义一个递归锁 其实是一把锁,然后可以acqurie多次 每次记录状态自加一,这样只有当状态为0 的时候才能被其他线程抢到
class Mythread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print("%s get the lock A" % self.name)
mutexB.acquire()
print("%s get the lock B" % self.name)
mutexA.release()
mutexB.release()
def f2(self):
mutexB.acquire()
print("%s get the lock B" % self.name)
time.sleep(7)
mutexA.acquire()
print("%s get the lock A" % self.name)
mutexA.release()
mutexB.release()
if __name__ == '__main__':
for i in range(10):
t = Mythread()
t.start()
3.信号量
信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,信号量同一时间可以有5个任务拿到锁去执行,如果说互斥锁是合租房屋的人去抢一个厕所,那么信号量就相当于一群路人争抢公共厕所,公共厕所有多个坑位,这意味着同一时间可以有多个人上公共厕所,但公共厕所容纳的人数是一定的,这便是信号量的大小。
import time
import random
from threading import Thread, Semaphore, current_thread
sm = Semaphore(3) # 设置信号量 3.py 同时允许3个人蹲坑
def task():
"""
:param :none
:return:
"""
with sm: # 文件上下文管理器,内部维护了enter 方法
print("<%s> in toilet!" % current_thread().name)
time.sleep(random.randint(1, 6))
print("<%s> in over!" % current_thread().name)
if __name__ == '__main__':
for i in range(10):
t = Thread(target=task)
t.start()
4.Event事件
线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行
# from threading import Thread, Event
# import time
# event = Event() # 先生成一个Event 对象
#
#
# def student(name):
# """
#
# :param name:
# :return:
# """
# print("%s is having classing!" % name)
# event.wait() # 学生等待老师说下课 这里就是 event wait 等待 set
# print("%s is having play games " % name)
#
#
# def teacher(name):
# """
#
# :param name:
# :return:
# """
# print("%s is having teaching!" % name)
# time.sleep(7)
# event.set() # 设置了set事件 之后 wait 的才执行下一步
# print("%s is having relaxing! " % name)
#
#
# if __name__ == '__main__':
# stu1 = Thread(target=student, args=("alex",))
# stu2 = Thread(target=student, args=("seven",))
# stu3 = Thread(target=student, args=("bob",))
# t1 = Thread(target=teacher, args=("boss",))
# stu1.start()
# stu2.start()
# stu3.start()
# t1.start()
from threading import Event
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
有多个工作线程尝试链接MySQL,我们想要在链接前确保MySQL服务正常才让那些工作线程去连接MySQL服务器,如果连接不成功,都会去尝试重新连接。那么我们就可以采用threading.Event机制来协调各个工作线程的连接操作
# from threading import Thread, Event, current_thread
# import time
# event = Event()
#
# 模拟检查数据库 并且链接
# def conn():
# """
#
# :return:
# """
# n = 1
# while not event.is_set(): # 返回标志位是否被设置 否为False
# if n == 4:
# return None
# event.wait(0.8) # 0.8秒之后我就不等他设置不设置了,他已经超时了 但是我必须有三次检测的尝试所以有个n
# print("%s is try connect to server %s times " % (current_thread().name, n))
# n += 1
# print("%s is connecting..." % current_thread().name) # 当检测成功我就链接 set=True 我就打印这句话 set=None我就执行while
#
#
#
# def check():
# """
#
# :return:
# """
# print("check the server is already !")
# time.sleep(2)
# event.set()
#
#
# if __name__ == '__main__':
# for i in range(3.py):
# c = Thread(target=conn,)
# c.start()
#
# ck = Thread(target=check,)
# ck.start()
***# 红路灯的意思模拟需要实现....***
5.定时器
定时器,指定n秒后执行某操作
from threading import Timer
def hello():
print("hello, world")
t = Timer(1, hello)
t.start() # after 1 seconds, "hello, world" will be printed
基于定时器 开发的每隔60秒刷新验证验证码功能
from threading import Thread, Timer
import time
import random
class Code:
def __init__(self):
"""
实例化类得时候我先执行male_cach 方法,来生成一个code
以后的事情就是我我的这个make_cach的方法都会有个定时器过interval时间执行本身
生成一个新的code 用以验证
"""
self.make_cach()
def make_cach(self, interval=5): #
"""
这个方法实现了 每五秒我就会去执行一下我本身
本身做的是:1.先运行make_code这个函数,
生成一个code验证码全局的验证码以便make_check调用
接着没过5秒我就会自动运行自己,来改变这个code的全局变量生成一个验证码
:param interval:
:return:
"""
self.code = self.make_code()
print(self.code)
self.t = Timer(interval, self.make_cach)
self.t.start()
def make_code(self, n=4): #
"""
生成验证码的方法 放在code类里面
:param n:create code length
:return:
"""
res = ""
for i in range(n):
s1 = str(random.randint(0, 9))
s2 = chr(random.randint(65, 90))
res += random.choice([s1, s2])
return res
def check(self):
"""
校验验证码的 方法,注意 因为这个self.code
一直是由于make_cack有一个定时器,导致这个值5秒就会变
make_cach这个方法其实就是没过5秒运行本身,更新 code的值
:return:
"""
while 1:
input_code = input("验证码请输入>>>:")
if input_code.upper() == self.code:
self.t.cancel()
print("ok !")
break
if __name__ == '__main__':
obj = Code()
obj.check()
线程之死锁、递归锁、信号量、事件Event 、定时器的更多相关文章
- Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures
参考博客: https://www.cnblogs.com/xiao987334176/p/9046028.html 线程简述 什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线 ...
- python 全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)
昨日内容回顾 线程什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的 一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的在当 ...
- python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03
目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...
- 并发编程---死锁||递归锁---信号量---Event事件---定时器
死锁 互斥锁:Lock(),互斥锁只能acquire一次 递归锁: RLock(),可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire # 死锁 f ...
- 同步锁 死锁与递归锁 信号量 线程queue event事件
二个需要注意的点: 1 线程抢的是GIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁Lock,其他线程也可以抢到GIL,但如果发现Lock任然没有被释放则阻塞,即便是拿到执行权限GIL也要 ...
- [并发编程 - 多线程:信号量、死锁与递归锁、时间Event、定时器Timer、线程队列、GIL锁]
[并发编程 - 多线程:信号量.死锁与递归锁.时间Event.定时器Timer.线程队列.GIL锁] 信号量 信号量Semaphore:管理一个内置的计数器 每当调用acquire()时内置计数器-1 ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- python开发线程:死锁和递归锁&信号量&定时器&线程queue&事件evevt
一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...
- python并发编程之线程(二):死锁和递归锁&信号量&定时器&线程queue&事件evevt
一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...
- GIL全局解释器锁-死锁与递归锁-信号量-event事件
一.全局解释器锁GIL: 官方的解释:掌握概念为主 """ In CPython, the global interpreter lock, or GIL, is a m ...
随机推荐
- Java数据封装类
项目中用到,比较好用!! 用户前端与后台的交互数据,这个封装类中包含分页.数据.错误码.状态码等信息!! 亲测好用哦! 一个类DataWrapper public class DataWrapper& ...
- Python 使用 os.fork() 创建子进程
Linux 操作系统提供了一个 fork() 函数用来创建子进程,这个函数很特殊,调用一次,返回两次,因为操作系统是将当前的进程(父进程)复制了一份(子进程),然后分别在父进程和子进程内返回.子进程永 ...
- EasyDSS RTMP流媒体服务器中调用videojs播放rtmp视频显示在左上角问题
本文转自EasyDarwin团队成员Penggy的博客:http://www.jianshu.com/p/f63f5b7c691b 问题描述: 近期我开发了一款新一代的RTMP/HLS流媒体服务器软件 ...
- D. Closest Equals(线段树)
题目链接: D. Closest Equals time limit per test 3 seconds memory limit per test 256 megabytes input stan ...
- dhcp snooping、ARP防护、
应用场景 无线客户端流动性很大和不确定,比如在外来人员比较多的地方:广场.大厅.会议室和接待室等等.使用该方案可以有效地避免因为无线端出现私设IP地址导致地址冲突或者客户端中ARP病毒发起ARP攻击的 ...
- openssl编译出错解决
tar -jxvf trafficserver-3.0.2.tar.bz2 ./configure --prefix=/usr/install/trafficserver --with-user=ca ...
- Postfix邮件黑名单和白名单
本文主要介绍如何用Postfix添加域名黑名单和白名单,用以处理垃圾邮件. 1.修改postfix主配置文件,增加限制语句 vim /etc/postfix/main.cf # 文末添加一行,限制往本 ...
- VMWare安装Ubuntu及配置开发环境遇到的问题集
安装完Ubuntu改为中文,发现是中英文混搭的界面 sudo apt-get install $(check-language-support --language=zh_CN)更新语言包. Ecli ...
- 浅谈Eclipse调用Tomcat服务的原理
浅谈Eclipse调用Tomcat服务的原理 转:http://www.thinksaas.cn/group/topic/341645/ 转:http://www.173it.cn/Html/?581 ...
- 让svn具有分布式的功能。
最近开发遇到了个难事.公司的svn库不能随便提交,必须要经过验证.但是平时修改太多,如果不提交到svn说不定前面被删掉的代码后面又需要了.svn自带的relocate和switch都不能达到要求.找遍 ...