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获取电脑硬件信息及状态的实现方法
Aug 29 Python
python模拟鼠标拖动操作的方法
Mar 11 Python
Python定义一个跨越多行的字符串的多种方法小结
Jul 19 Python
使用Python编写Prometheus监控的方法
Oct 15 Python
python3 小数位的四舍五入(用两种方法解决round 遇5不进)
Apr 11 Python
Django rstful登陆认证并检查session是否过期代码实例
Aug 13 Python
python requests更换代理适用于IP频率限制的方法
Aug 21 Python
Python中最好用的命令行参数解析工具(argparse)
Aug 23 Python
Python基础之函数基本用法与进阶详解
Jan 02 Python
Python Web项目Cherrypy使用方法镜像
Nov 05 Python
Python实现淘宝秒杀功能的示例代码
Jan 19 Python
python3中celery异步框架简单使用+守护进程方式启动
Jan 20 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
第十三节 对象串行化 [13]
2006/10/09 PHP
php入门教程 精简版
2009/12/13 PHP
php自动获取字符串编码函数mb_detect_encoding
2011/05/31 PHP
PHP swfupload图片上传的实例代码
2013/09/30 PHP
php 模拟 asp.net webFrom 按钮提交事件实例
2014/10/13 PHP
ThinkPHP 5.x远程命令执行漏洞复现
2019/09/23 PHP
prototype 中文参数乱码解决方案
2009/11/09 Javascript
jQuery 名称冲突的解决方法
2011/04/08 Javascript
浅谈js中字符和数组一些基本算法题
2016/08/15 Javascript
Websocket协议详解及简单实例代码
2016/12/12 Javascript
详解vue-router2.0动态路由获取参数
2017/06/14 Javascript
详解react-native WebView 返回处理(非回调方法可解决)
2018/02/27 Javascript
如何从零开始利用js手写一个Promise库详解
2018/04/19 Javascript
Vue表单类的父子组件数据传递示例
2018/05/03 Javascript
Bootstrap Table中的多选框删除功能
2018/07/15 Javascript
angularjs实现对表单输入改变的监控(ng-change和watch两种方式)
2018/08/29 Javascript
Vue实现本地购物车功能
2018/12/05 Javascript
vue的列表交错过渡实现代码示例
2019/05/05 Javascript
jqGrid表格底部汇总、合计行footerrow处理
2019/08/21 Javascript
vue项目开启Gzip压缩和性能优化操作
2020/10/26 Javascript
[01:13:46]iG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python实现zencart产品数据导入到magento(python导入数据)
2014/04/03 Python
Python实现把xml或xsl转换为html格式
2015/04/08 Python
Python 爬虫学习笔记之多线程爬虫
2016/09/21 Python
Python文件操作,open读写文件,追加文本内容实例
2016/12/14 Python
python3下使用cv2.imwrite存储带有中文路径图片的方法
2018/05/10 Python
树莓派用python中的OpenCV输出USB摄像头画面
2019/06/22 Python
Python tempfile模块生成临时文件和临时目录
2020/09/30 Python
Window10上Tensorflow的安装(CPU和GPU版本)
2020/12/15 Python
Clarks鞋澳大利亚官方网站:Clarks Australia
2019/12/25 全球购物
俄罗斯皮肤健康中心:Pharmacosmetica.ru
2020/02/22 全球购物
大学生职业规划范文:象牙塔生活的四年计划
2014/01/14 职场文书
社区十八大感言
2014/01/19 职场文书
艺术节主持词
2014/04/02 职场文书
化工见习报告范文
2014/10/31 职场文书
英文版辞职信
2015/02/28 职场文书