Python多线程编程(四):使用Lock互斥锁


Posted in Python onApril 05, 2015

前面已经演示了Python:使用threading模块实现多线程编程二两种方式起线程和Python:使用threading模块实现多线程编程三threading.Thread类的重要函数,这两篇文章的示例都是演示了互不相干的独立线程,现在我们考虑这样一个问题:假设各个线程需要访问同一公共资源,我们的代码该怎么写?

''' 

Created on 2012-9-8 

 

@author: walfred 

@module: thread.ThreadTest3 

'''  

import threading  

import time  

 

counter = 0  

 

class MyThread(threading.Thread):  

    def __init__(self):  

        threading.Thread.__init__(self)  

 

    def run(self):  

        global counter  

        time.sleep(1);  

        counter += 1  

        print "I am %s, set counter:%s" % (self.name, counter)  

 

if __name__ == "__main__":  

    for i in range(0, 200):  

        my_thread = MyThread()  

        my_thread.start()

解决上面的问题,我们兴许会写出这样的代码,我们假设跑200个线程,但是这200个线程都会去访问counter这个公共资源,并对该资源进行处理(counter += 1),代码看起来就是这个样了,但是我们看下运行结果:

I am Thread-69, set counter:64

I am Thread-73, set counter:66I am Thread-74, set counter:67I am Thread-75, set counter:68I am Thread-76, set counter:69I am Thread-78, set counter:70I am Thread-77, set counter:71I am Thread-58, set counter:72I am Thread-60, set counter:73I am Thread-62, set counter:74I am Thread-66,set counter:75I am Thread-70, set counter:76I am Thread-72, set counter:77I am Thread-79, set counter:78I am Thread-71, set counter:78

打印结果我只贴了一部分,从中我们已经看出了这个全局资源(counter)被抢占的情况,问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。在开发过程中我们必须要避免这种情况,那怎么避免?这就用到了我们在综述中提到的互斥锁了。

互斥锁概念

Python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。在Python中我们使用threading模块提供的Lock类。

我们对上面的程序进行整改,为此我们需要添加一个互斥锁变量mutex = threading.Lock(),然后在争夺资源的时候之前我们会先抢占这把锁mutex.acquire(),对资源使用完成之后我们在释放这把锁mutex.release()。代码如下:

''' 

Created on 2012-9-8 

 

@author: walfred 

@module: thread.ThreadTest4 

'''  

 

import threading  

import time  

 

counter = 0  

mutex = threading.Lock()  

 

class MyThread(threading.Thread):  

    def __init__(self):  

        threading.Thread.__init__(self)  

 

    def run(self):  

        global counter, mutex  

        time.sleep(1);  

        if mutex.acquire():  

            counter += 1  

            print "I am %s, set counter:%s" % (self.name, counter)  

            mutex.release()  

 

if __name__ == "__main__":  

    for i in range(0, 100):  

        my_thread = MyThread()  

        my_thread.start()

同步阻塞

当一个线程调用Lock对象的acquire()方法获得锁时,这把锁就进入“locked”状态。因为每次只有一个线程1可以获得锁,所以如果此时另一个线程2试图获得这个锁,该线程2就会变为“blo同步阻塞状态。直到拥有锁的线程1调用锁的release()方法释放锁之后,该锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

进一步考虑

通过对公共资源使用互斥锁,这样就简单的到达了我们的目的,但是如果我们又遇到下面的情况:

遇到锁嵌套的情况该怎么办,这个嵌套是指当我一个线程在获取临界资源时,又需要再次获取;
如果有多个公共资源,在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源;

上述这两种情况会直接造成程序挂起,即死锁,下面我们会谈死锁及可重入锁RLock。

Python 相关文章推荐
python使用wmi模块获取windows下硬盘信息的方法
May 15 Python
Python实现将一个大文件按段落分隔为多个小文件的简单操作方法
Apr 17 Python
解决PyCharm控制台输出乱码的问题
Jan 16 Python
浅谈Python反射 & 单例模式
Mar 21 Python
十分钟搞定pandas(入门教程)
Jun 21 Python
Python浮点数四舍五入问题的分析与解决方法
Nov 19 Python
TensorFlow2.0矩阵与向量的加减乘实例
Feb 07 Python
Python+Appium实现自动抢微信红包
May 21 Python
PyTorch dropout设置训练和测试模式的实现
May 27 Python
python opencv旋转图片的使用方法
Jun 04 Python
Python的三个重要函数详解
Jan 18 Python
使用python创建股票的时间序列可视化分析
Mar 03 Python
Python多线程编程(三):threading.Thread类的重要函数和方法
Apr 05 #Python
Python多线程编程(二):启动线程的两种方法
Apr 05 #Python
Python多线程编程(一):threading模块综述
Apr 05 #Python
Python中使用dom模块生成XML文件示例
Apr 05 #Python
Python中比较特别的除法运算和幂运算介绍
Apr 05 #Python
Python中使用logging模块打印log日志详解
Apr 05 #Python
Python中的两个内置模块介绍
Apr 05 #Python
You might like
PHP中date()日期函数有关参数整理
2011/07/19 PHP
smarty模板引擎中内建函数if、elseif和else的使用方法
2015/01/22 PHP
php微信开发之带参数二维码的使用
2016/08/03 PHP
PHP基于IMAP收取邮件的方法示例
2017/08/07 PHP
php中html_entity_decode实现HTML实体转义
2018/06/13 PHP
类似CSDN图片切换效果脚本
2009/09/17 Javascript
使用 JScript 创建 .exe 或 .dll 文件的方法
2011/07/13 Javascript
FireBug 调试JS入门教程 如何调试JS
2013/12/23 Javascript
jquery toolbar与网页浮动工具条具体实现代码
2014/01/12 Javascript
AngularJS学习笔记之TodoMVC的分析
2015/02/22 Javascript
JS+CSS实现仿雅虎另类滑动门切换效果
2015/10/13 Javascript
jquery.validate 自定义验证方法及validate相关参数
2016/01/18 Javascript
详解bootstrap用dropdown-menu实现上下文菜单
2017/09/22 Javascript
Angular表格神器ui-grid应用详解
2017/09/29 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
react用Redux中央仓库实现一个todolist
2019/09/29 Javascript
原生js实现自定义消息提示框
2020/11/19 Javascript
js动态生成表格(节点操作)
2021/01/12 Javascript
[06:45]DOTA2卡尔工作室 英雄介绍幻影长矛手篇
2013/07/12 DOTA
[03:24]2014DOTA2国际邀请赛 神秘商店生意火爆
2014/07/18 DOTA
[36:05]DOTA2亚洲邀请赛 3.31 小组赛 A组 Liquid vs Optic
2018/04/01 DOTA
Python脚本实现格式化css文件
2015/04/08 Python
利用PyInstaller将python程序.py转为.exe的方法详解
2017/05/03 Python
python实现月食效果实例代码
2019/06/18 Python
浅谈Python 敏感词过滤的实现
2019/08/15 Python
HTML5对手机页面长按会粘贴复制禁用的解决方法
2016/07/19 HTML / CSS
HTML5的标签的代码的简单介绍 HTML5标签的简介
2012/05/28 HTML / CSS
法国面料和小百货在线商店:Mondial Tissus
2019/03/23 全球购物
澳大利亚一站式数码相机商店:CameraPro
2020/03/09 全球购物
学校门卫工作职责
2013/12/07 职场文书
副乡长群众路线教育实践活动个人对照检查材料
2014/09/19 职场文书
教师学习八项规定六项禁令思想汇报
2014/09/27 职场文书
长江三峡导游词
2015/01/31 职场文书
Python下opencv库的安装过程及问题汇总
2021/06/11 Python
使用 Apache Superset 可视化 ClickHouse 数据的两种方法
2021/07/07 Servers
详解Java七大阻塞队列之SynchronousQueue
2021/09/04 Java/Android