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数据库操作常用功能使用详解(创建表/插入数据/获取数据)
Dec 06 Python
Python中多线程及程序锁浅析
Jan 21 Python
Python2.x中文乱码问题解决方法
Jun 02 Python
Python处理PDF及生成多层PDF实例代码
Apr 24 Python
Python对字符串实现去重操作的方法示例
Aug 11 Python
对Python中gensim库word2vec的使用详解
May 08 Python
pygame游戏之旅 游戏中添加显示文字
Nov 20 Python
pip安装python库的方法总结
Aug 02 Python
python 魔法函数实例及解析
Sep 25 Python
Django与pyecharts结合的实例代码
May 13 Python
python中np是做什么的
Jul 21 Python
Python3合并两个有序数组代码实例
Aug 11 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 magic_quotes_gpc的一点认识与分析
2008/08/18 PHP
PHP pathinfo()获得文件的路径、名称等信息说明
2011/09/13 PHP
基于curl数据采集之单页面采集函数get_html的使用
2013/04/28 PHP
PHP 观察者模式的实现代码
2013/05/10 PHP
md5 16位二进制与32位字符串相互转换示例
2013/12/30 PHP
PHP实现自动识别Restful API的返回内容类型
2015/02/07 PHP
PHP生成条形码大揭秘
2015/09/24 PHP
PHP中类的自动加载的方法
2017/03/17 PHP
php-fpm开启状态统计的方法详解
2017/06/23 PHP
防止页面被iframe(兼容IE,Firefox火狐)
2010/07/04 Javascript
Egret引擎开发指南之创建项目
2014/09/03 Javascript
JQuery显示、隐藏div的几种方法简明总结
2015/04/16 Javascript
AngularJS中使用HTML5手机摄像头拍照
2016/02/22 Javascript
bootstrap table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)代码分享
2017/01/24 Javascript
Bootstrap 模态框多次显示后台提交多次BUG的解决方法
2017/12/26 Javascript
jQuery中复合选择器简单用法示例
2018/03/31 jQuery
javaScript实现一个队列的方法
2020/07/14 Javascript
[57:38]2018DOTA2亚洲邀请赛3月30日 小组赛A组 OpTic VS OG
2018/03/31 DOTA
Python实现自动为照片添加日期并分类的方法
2017/09/30 Python
Python学习pygal绘制线图代码分享
2017/12/09 Python
用python实现的线程池实例代码
2018/01/06 Python
python负载均衡的简单实现方法
2018/02/04 Python
python微信跳一跳系列之色块轮廓定位棋盘
2018/02/26 Python
Python Django 命名空间模式的实现
2019/08/09 Python
Python大数据之网络爬虫的post请求、get请求区别实例分析
2019/11/16 Python
Python面向对象中类(class)的简单理解与用法分析
2020/02/21 Python
Java Spring项目国际化(i18n)详细方法与实例
2020/03/20 Python
Flask模板引擎Jinja2使用实例
2020/04/23 Python
出门问问全球官方商城:Tichome音箱和TicWatch智能手表
2017/12/02 全球购物
德国滑雪和户外用品网上商店:XSPO
2019/10/30 全球购物
《宋庆龄故居的樟树》教学反思
2014/04/07 职场文书
计算机软件专业求职信
2014/06/10 职场文书
羽毛球社团活动总结
2014/06/27 职场文书
三方协议书
2015/01/27 职场文书
迎新年主持词
2015/07/06 职场文书
用CSS3画一个爱心
2021/04/27 HTML / CSS