“死锁” 与 python多线程之threading模块下的锁机制
2016-06-04 00:31
537 查看
一:死锁
在死锁之前需要先了解的概念是“可抢占资源”与“不可抢占资源”【此处的资源可以是硬件设备也可以是一组信息】,因为死锁是与不可抢占资源有关的。
可抢占资源:可以从拥有他的进程中抢占而不会发生副作用。e.g:存储器就是一类可抢占资源(假设有A, B两个进程都想用打印机对256MB的用户内存进行打印,若A已经获得打印机并且开始打印,但是在没有打印完成其时间片就用完并被换出了,此时B进程开始运行“抢占了”内存并开始请求打印机,但是A进程还拥有打印机所以B进程没有抢占打印机成功,此时由于双方都缺少一个对方拥有的资源,双方都不能执行,有死锁的危险,不过实际上系统会把进程B换出内存,重新将进程A换入内存 [也就是A进程反过来抢占了B进程的内存资源],效果也就是进程A继续执行直到完成并释放打印机,而后B进程就能够执行了)。从中可以看出由于可抢占资源可以通过重新分配资源而避免了死锁的发生,所以可抢占资源是不会发生死锁现象的。
不可抢占资源:在不引起相关计算失败的情况下,无法把它从占有它的进程处抢占过来的资源。e.g:刻录机(假设一个进程已经开始刻盘,突然将刻录机分配给另一个进程,那么将划坏CD盘,所以任何时候刻录机都是不能被抢占的)
死锁:当多个进程需要排他性的访问多个资源,且其所需要的资源在同一时间属于不同进程且还是不可抢占资源的时候,此时相关进程就会一直请求对应资源但得不到从而一直阻塞下去,这就是死锁现象。
*除了硬件机器与I/O设备之外,别的情况也可能引起死锁,比如一个数据库系统中,为了避免竞争可对若干记录加锁,假设进程A对记录R1加锁而进程B岁记录R2加锁,接着他们又各自试着加锁对方的记录,此时也会发生死锁
注:关于GIL(global interpreter lock),可参见这篇文章:http://www.dabeaz.com/python/UnderstandingGIL.pdf
二:Threading模块
2.1.threading.Thread对象【创建线程的主要对象】:
方法:start():启动线程
run():启动线程后自动调用的方法
join([timeout]):等待到被调用的线程终止
is_alive():返回线程活动状态
属性:name:线程名
ident:线程ID号
daemon:后台标志
2.2.创建线程的方法:
1:实例化threading.Thread对象
ths = threading.Thread( target = None, name = None, args = (), kwarg = {} )
传入函数名 线程名 函数的参数
2:继承threading中的Thread对象后再实例化并启动
2.3.以不同的线程类型分:
令:t = threading.Thread(target=dmn...),即是t为一个线程
2.3.1.独立线程:就是最简单的独立单线程
2.3.2.线程等待:t.join([timeout]),放到start()后,表明t线程执行完后(或是指定时间后)才轮到下一个线程【若是因为指定时间的话还会跳回t线程】
线程间通信锁示例
*补充.关于定时执行:threading.Timer()
参考:
《现代操作系统》---Andrew S. Tanebaum
在死锁之前需要先了解的概念是“可抢占资源”与“不可抢占资源”【此处的资源可以是硬件设备也可以是一组信息】,因为死锁是与不可抢占资源有关的。
可抢占资源:可以从拥有他的进程中抢占而不会发生副作用。e.g:存储器就是一类可抢占资源(假设有A, B两个进程都想用打印机对256MB的用户内存进行打印,若A已经获得打印机并且开始打印,但是在没有打印完成其时间片就用完并被换出了,此时B进程开始运行“抢占了”内存并开始请求打印机,但是A进程还拥有打印机所以B进程没有抢占打印机成功,此时由于双方都缺少一个对方拥有的资源,双方都不能执行,有死锁的危险,不过实际上系统会把进程B换出内存,重新将进程A换入内存 [也就是A进程反过来抢占了B进程的内存资源],效果也就是进程A继续执行直到完成并释放打印机,而后B进程就能够执行了)。从中可以看出由于可抢占资源可以通过重新分配资源而避免了死锁的发生,所以可抢占资源是不会发生死锁现象的。
不可抢占资源:在不引起相关计算失败的情况下,无法把它从占有它的进程处抢占过来的资源。e.g:刻录机(假设一个进程已经开始刻盘,突然将刻录机分配给另一个进程,那么将划坏CD盘,所以任何时候刻录机都是不能被抢占的)
死锁:当多个进程需要排他性的访问多个资源,且其所需要的资源在同一时间属于不同进程且还是不可抢占资源的时候,此时相关进程就会一直请求对应资源但得不到从而一直阻塞下去,这就是死锁现象。
*除了硬件机器与I/O设备之外,别的情况也可能引起死锁,比如一个数据库系统中,为了避免竞争可对若干记录加锁,假设进程A对记录R1加锁而进程B岁记录R2加锁,接着他们又各自试着加锁对方的记录,此时也会发生死锁
注:关于GIL(global interpreter lock),可参见这篇文章:http://www.dabeaz.com/python/UnderstandingGIL.pdf
二:Threading模块
2.1.threading.Thread对象【创建线程的主要对象】:
方法:start():启动线程
run():启动线程后自动调用的方法
join([timeout]):等待到被调用的线程终止
is_alive():返回线程活动状态
属性:name:线程名
ident:线程ID号
daemon:后台标志
2.2.创建线程的方法:
1:实例化threading.Thread对象
ths = threading.Thread( target = None, name = None, args = (), kwarg = {} )
传入函数名 线程名 函数的参数
2:继承threading中的Thread对象后再实例化并启动
2.3.以不同的线程类型分:
令:t = threading.Thread(target=dmn...),即是t为一个线程
2.3.1.独立线程:就是最简单的独立单线程
2.3.2.线程等待:t.join([timeout]),放到start()后,表明t线程执行完后(或是指定时间后)才轮到下一个线程【若是因为指定时间的话还会跳回t线程】
#coding:utf-8 import threading, time class WaitThread(threading.Thread): def run(self): self.name = "等待线程" print(self.name,"正在等待") #注意此程序的执行顺序,先调用的此线程执行到这里 **event.wait()** #在此此线程wait进入线程池等待,切换到mainThread直至设置标志 print(self.name,"启动了") #从而此线程在此被唤醒执行 **event.clear()** #而后设置标志为false class MainThread(threading.Thread): def run(self): time.sleep(3) print("主线程更改了标志") **event.set()** print("这里的会在WaitThread打印启动了前打印吗?") **event = threading.Event()** if __name__ == "__main__": wt = WaitThread() mt = MainThread() wt.start() mt.start() # 输出: # 等待线程 正在等待 # 主线程更改了标志 # 这里的会在WaitThread打印启动了前打印吗? # 等待线程 启动了
线程间通信锁示例
*补充.关于定时执行:threading.Timer()
参考:
《现代操作系统》---Andrew S. Tanebaum
相关文章推荐
- python2.0 s12 day8 _ python线程&python进程
- 开始入坑-大蟒蛇首发
- PySpider python 爬虫
- Python文件操作
- Python基于sklearn库的分类算法简单应用示例
- 使用Python的Flask框架来搭建第一个Web应用程序
- Python输出汉字字库及将文字转换为图片的方法
- Python中import导入上一级目录模块及循环import问题的解决
- 详解Python中open()函数指定文件打开方式的用法
- 举例讲解Python中字典的合并值相加与异或对比
- 全面理解Python中self的用法
- Python中规范定义命名空间的一些建议
- 在Python的Flask框架中构建Web表单的教程
- 使用Python的Flask框架构建大型Web应用程序的结构示例
- python装饰器
- 20.python的文件处理
- 关于Python中split函数那些事
- Python eclipse开发环境搭建
- python logging - 初级
- python 装饰器传参