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 相关文章推荐
Python3.x版本中新的字符串格式化方法
Apr 24 Python
举例讲解Python中metaclass元类的创建与使用
Jun 30 Python
基于python的七种经典排序算法(推荐)
Dec 08 Python
Python基于socket实现简单的即时通讯功能示例
Jan 16 Python
深入浅析python with语句简介
Apr 11 Python
Python基于xlrd模块操作Excel的方法示例
Jun 21 Python
Python OpenCV处理图像之图像直方图和反向投影
Jul 10 Python
python 检查文件mime类型的方法
Dec 08 Python
pytorch实现从本地加载 .pth 格式模型
Feb 14 Python
python 实现人和电脑猜拳的示例代码
Mar 02 Python
基于Python的一个自动录入表格的小程序
Aug 05 Python
python实现简单的tcp 文件下载
Sep 16 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 php_openssl.dll的作用
2013/07/01 PHP
php模仿asp Application对象在线人数统计实现方法
2015/01/04 PHP
WordPress自定义时间显示格式
2015/03/27 PHP
PHP生成树的方法
2015/07/28 PHP
PHP多维数组转一维数组的简单实现方法
2015/12/23 PHP
php+js实现百度地图多点标注的方法
2016/11/30 PHP
CodeIgniter整合Smarty的方法详解
2017/08/25 PHP
JavaScript 中的事件教程
2007/04/05 Javascript
JQuery的一些小应用收集
2010/03/27 Javascript
分享一个自定义的console类 让你不再纠结JS中的调试代码的兼容
2012/04/20 Javascript
Javascript图像处理—亮度对比度应用案例
2013/01/03 Javascript
向当前style sheet中插入一个新的style实现方法
2013/04/01 Javascript
jQuery extend 的简单实例
2013/09/18 Javascript
鼠标左键单击冲突的问题解决方法(防止冒泡)
2014/05/14 Javascript
node.js中的fs.open方法使用说明
2014/12/17 Javascript
js实现遮罩层弹出框的方法
2015/01/15 Javascript
JavaScript严格模式详解
2015/11/18 Javascript
基于JQuery实现图片轮播效果(焦点图)
2016/02/02 Javascript
JavaScript创建对象的七种方式全面总结
2017/08/21 Javascript
vue-router 路由基础的详解
2017/10/17 Javascript
js数据类型检测总结
2018/08/05 Javascript
详解Eslint 配置及规则说明
2018/09/10 Javascript
JavaScript实现复选框全选和取消全选
2020/11/20 Javascript
python实现爬虫统计学校BBS男女比例(一)
2015/12/31 Python
Python切片知识解析
2016/03/06 Python
python添加模块搜索路径方法
2017/09/11 Python
python实现ID3决策树算法
2017/12/20 Python
python 格式化输出百分号的方法
2019/01/20 Python
使用python实现数组、链表、队列、栈的方法
2019/12/20 Python
python ssh 执行shell命令的示例
2020/09/29 Python
python Scrapy框架原理解析
2021/01/04 Python
CSS3实现千变万化的文字阴影text-shadow效果设计
2016/04/26 HTML / CSS
意大利奢侈品综合电商网站:MODES
2019/12/14 全球购物
2014年教师节演讲稿范文
2014/09/10 职场文书
利用Nginx代理如何解决前端跨域问题详析
2021/04/02 Servers
浅谈mysql哪些情况会导致索引失效
2021/11/20 MySQL