Python--同步锁(互斥锁)、死锁(状态)、递归锁、信号量、Event对象
同步锁/互斥锁 (Lock)
import time
import threading def sub():
global num #在每个线程中都获取这个全局变量
#num-=1 temp=num
time.sleep(0.1)
num =temp-1 # 对此公共变量进行-1操作 num = 100 #设定一个共享变量 thread_list = [] for i in range(100):
t = threading.Thread(target=sub)
t.start()
thread_list.append(t) for t in thread_list: #等待所有线程执行完毕
t.join() print('Result: ', num)
运行结果:
99
我们想要的结果是多线程实现递减至0 ,但是很明显没有实现。
下面这段代码更改了一下睡眠时间,依然结果不会是0 。
import time
import threading def sub():
global num #在每个线程中都获取这个全局变量
#num-=1 temp=num
time.sleep(0.001)
num =temp-1 # 对此公共变量进行-1操作 num = 100 #设定一个共享变量 thread_list = [] for i in range(100):
t = threading.Thread(target=sub)
t.start()
thread_list.append(t) for t in thread_list: #等待所有线程执行完毕
t.join() print('Result: ', num)
运行结果:
大于0 但是小于100的数
锁通常被用来实现对共享资源的同步访问。
import threading R=threading.Lock() #为每一个共享资源创建一个Lock对象 R.acquire() #当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放)
'''
对公共数据的操作
'''
R.release() #待资源访问完后,再调用release方法释放锁:
import time
import threading def sub():
global num #在每个线程中都获取这个全局变量 lock.acquire()
temp=num
time.sleep(0.001)
num =temp-1 # 对此公共变量进行-1操作
lock.release() num = 100 #设定一个共享变量
thread_list = []
lock=threading.Lock() for i in range(100):
t = threading.Thread(target=sub)
t.start()
thread_list.append(t) for t in thread_list: #等待所有线程执行完毕
t.join() print('Result: ', num)
运行结果:
Result: 0
这样就解决了我们的问题。
为什么有了GIL,还需要线程同步? 多线程环境下必须存在资源的竞争,那么如何才能保证同一时刻只有一个线程对共享资源进行存取? 加锁, 对, 加锁可以保证存取操作的唯一性, 从而保证同一时刻只有一个线程对共享数据存取.
死锁与递归锁
import time
import threading
class Mythread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
self.foo() def foo(self):
locka.acquire()
print('I am %s got locka---%s'%(self.name,time.ctime())) lockb.acquire()
print('I am %s got lockb---%s'%(self.name,time.ctime())) lockb.release()
locka.release() if __name__ == '__main__':
locka=threading.Lock()
lockb=threading.Lock() for i in range(10):
t=Mythread()
t.start()
运行效果:
I am Thread-1 got locka---Fri Jul 21 14:30:32 2017
I am Thread-1 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-2 got locka---Fri Jul 21 14:30:32 2017
I am Thread-2 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-3 got locka---Fri Jul 21 14:30:32 2017
I am Thread-3 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-4 got locka---Fri Jul 21 14:30:32 2017
I am Thread-4 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-5 got locka---Fri Jul 21 14:30:32 2017
I am Thread-5 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-6 got locka---Fri Jul 21 14:30:32 2017
I am Thread-6 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-7 got locka---Fri Jul 21 14:30:32 2017
I am Thread-7 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-8 got locka---Fri Jul 21 14:30:32 2017
I am Thread-8 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-9 got locka---Fri Jul 21 14:30:32 2017
I am Thread-9 got lockb---Fri Jul 21 14:30:32 2017
I am Thread-10 got locka---Fri Jul 21 14:30:32 2017
I am Thread-10 got lockb---Fri Jul 21 14:30:32 2017

所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
import time
import threading
class Mythread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
self.foo()
self.bar() def foo(self):
locka.acquire()
print('I am %s got locka---%s'%(self.name,time.ctime())) lockb.acquire()
print('I am %s got lockb---%s'%(self.name,time.ctime())) lockb.release()
locka.release() def bar(self):
lockb.acquire()
print('I am %s got lockb---%s'%(self.name,time.ctime())) locka.acquire()
print('I am %s got locka---%s'%(self.name,time.ctime())) locka.release()
lockb.release() if __name__ == '__main__':
locka=threading.Lock()
lockb=threading.Lock() for i in range(10):
t=Mythread()
t.start()
运行效果图:

解决死锁状态的递归锁出现了。
在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:
import time
import threading class Mythread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self) def run(self):
self.foo()
self.bar() def foo(self):
Rlock.acquire()
print('I am %s got locka---%s'%(self.name,time.ctime())) Rlock.acquire()
print('I am %s got lockb---%s'%(self.name,time.ctime())) Rlock.release()
Rlock.release() def bar(self):
Rlock.acquire()
print('I am %s got lockb---%s'%(self.name,time.ctime())) Rlock.acquire()
print('I am %s got locka---%s'%(self.name,time.ctime())) Rlock.release()
Rlock.release() if __name__ == '__main__':
Rlock=threading.RLock() for i in range(10):
t=Mythread()
t.start()
运行效果:
I am Thread-1 got locka---Fri Jul 21 14:42:08 2017
I am Thread-1 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-2 got locka---Fri Jul 21 14:42:08 2017
I am Thread-2 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-2 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-2 got locka---Fri Jul 21 14:42:08 2017
I am Thread-1 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-1 got locka---Fri Jul 21 14:42:08 2017
I am Thread-3 got locka---Fri Jul 21 14:42:08 2017
I am Thread-3 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-4 got locka---Fri Jul 21 14:42:08 2017
I am Thread-4 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-5 got locka---Fri Jul 21 14:42:08 2017
I am Thread-5 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-3 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-3 got locka---Fri Jul 21 14:42:08 2017
I am Thread-6 got locka---Fri Jul 21 14:42:08 2017
I am Thread-6 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-6 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-6 got locka---Fri Jul 21 14:42:08 2017
I am Thread-4 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-4 got locka---Fri Jul 21 14:42:08 2017
I am Thread-7 got locka---Fri Jul 21 14:42:08 2017
I am Thread-7 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-7 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-7 got locka---Fri Jul 21 14:42:08 2017
I am Thread-9 got locka---Fri Jul 21 14:42:08 2017
I am Thread-9 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-9 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-9 got locka---Fri Jul 21 14:42:08 2017
I am Thread-5 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-5 got locka---Fri Jul 21 14:42:08 2017
I am Thread-10 got locka---Fri Jul 21 14:42:08 2017
I am Thread-10 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-10 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-10 got locka---Fri Jul 21 14:42:08 2017
I am Thread-8 got locka---Fri Jul 21 14:42:08 2017
I am Thread-8 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-8 got lockb---Fri Jul 21 14:42:08 2017
I am Thread-8 got locka---Fri Jul 21 14:42:08 2017
Semaphore(信号量)
Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
实例:(同时只有5个线程可以获得semaphore,即可以限制最大连接数为5):
import threading
import time semaphore =threading.Semaphore(5) #同时只有5个线程可以获得semaphore,即可以限制最大连接数为5 def foo():
semaphore.acquire()
time.sleep(2)
print('ok')
semaphore.release() for i in range(10):
t=threading.Thread(target=foo)
t.start()
运行效果:
先同时打印5个‘ok’,过两秒再同时打印5个‘ok’
Event对象
线程的一个关键特性是每个线程都是独立运行且状态不可预测。
如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就 会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。
在 初始情况下,Event对象中的信号标志被设置为假。
如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。
一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。
如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行
event.isSet():返回event的状态值; event.wait():如果 event.isSet()==False将阻塞线程; event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度; event.clear():恢复event的状态值为False。

import threading,time event=threading.Event() def foo():
print('waitting...')
event.wait()
print('connect to redis server') for i in range(5):
t=threading.Thread(target=foo)
t.start() print('attempt to start redis server')
time.sleep(3) event.set()
运行效果:
先同时打印5个'waiting'和'attempt to start redis server',3秒后打印5个'connect to redis server'
threading.Event的wait方法还接受一个超时参数,默认情况下如果事件一直没有发生,wait方法会一直阻塞下去,而加入这个超时参数之后,如果阻塞时间超过这个参数设定的值之后,wait方法会返回。
import threading,time event=threading.Event() def foo():
print('waitting...')
event.wait(1)
print('cinnect to redis server') for i in range(5):
t=threading.Thread(target=foo)
t.start() print('attempt to start redis server')
time.sleep(3) event.set()
运行效果:
先同时打印5个‘waitting’,1个‘attempt to start redis server’,过1秒打印'cinnect to redis server',再过两秒程序运行结束
Python--同步锁(互斥锁)、死锁(状态)、递归锁、信号量、Event对象的更多相关文章
- 并发、并行、同步、异步、全局解释锁GIL、同步锁Lock、死锁、递归锁、同步对象/条件、信号量、队列、生产者消费者、多进程模块、进程的调用、Process类、
并发:是指系统具有处理多个任务/动作的能力. 并行:是指系统具有同时处理多个任务/动作的能力. 并行是并发的子集. 同步:当进程执行到一个IO(等待外部数据)的时候. 异步:当进程执行到一个IO不等到 ...
- Python之网路编程之死锁,递归锁,信号量,Event事件,线程Queue
一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...
- Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures
参考博客: https://www.cnblogs.com/xiao987334176/p/9046028.html 线程简述 什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线 ...
- python 全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)
昨日内容回顾 线程什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的 一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的在当 ...
- Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量
在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...
- python全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)
昨日内容回顾 线程 什么是线程? 线程是cpu调度的最小单位 进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的 ...
- python多线程,event,互斥锁,死锁,递归锁,信号量
Python多线程/event 多线程-threading python的thread模块是⽐较底层的模块, python的threading模块是对thread做了⼀些包装的, 可以更加⽅便的被使⽤ ...
- Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- 26 python 初学(线程、同步锁、死锁和递归锁)
参考博客: www.cnblogs.com/yuanchenqi/articles/5733873.html 并发:一段时间内做一些事情 并行:同时做多件事情 线程是操作系统能够进行运算调度的基本单位 ...
- 第十五章、Python多线程同步锁,死锁和递归锁
目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...
随机推荐
- ASIO
{ 编译ASIO库时,出现编译警告, "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n& ...
- PHP curl_copy_handle函数
curl_copy_handle — 复制一个cURL句柄和它的所有选项 说明 resource curl_copy_handle ( resource $ch ) 复制一个cURL句柄并保持相同的选 ...
- codeforces798C - Mike and gcd problem (数论+思维)
原题链接:http://codeforces.com/contest/798/problem/C 题意:有一个数列A,gcd(a1,a2,a3...,an)>1 时称这个数列是“漂亮”的.存在这 ...
- 【Linux】清理缓存buffer/cache
运行sync将dirty的内容写回硬盘 sync 通过修改proc系统的drop_caches清理free的cache echo 3 > /proc/sys/vm/drop_caches ech ...
- 10.17 linux 文件权限
文件权限模拟练习 [root@wen ~]# groupadd incahome[root@wen ~]# usersdd oldboy -g incahome-bash: usersdd: comm ...
- 【c#技术】一篇文章搞掂:Newtonsoft.Json Json.Net
一.介绍 Json.Net是一个.Net高性能框架. 特点和好处: 1.为.Net对象和JSON之间的转换提供灵活的Json序列化器: 2.为阅读和书写JSON提供LINQ to JSON: 3.高性 ...
- flask 实现简易图书管理
""" 1.配置数据库 a.导入 SQLalchemy库 b.创建db对象,并配置参数 c.创建数据库 2.添加书和作者的模型 a.模型集成db.Model b.__ta ...
- 左手Mongodb右手Redis 第三章mongdb操作
mongodb查询操作 1.查询操作 db.getCollection('example_data_1').find({}) 查询所有的信息,相当于mysql中的select * from tabl ...
- Redis详细用法
Redis详细用法 1.redis启动命令 本机Redis 安装路径是在usr/local/redis 目录下 启动命令: ./redis-server redis.conf(启动时指定配置文件) 测 ...
- Maven Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
因此:maven中,配置文件的读取应有下列红字两部分,缺一不可. 不是maven项目时,可以都不写........ <context-param> <param-name>co ...