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字符转换
Sep 06 Python
python中的字典详细介绍
Sep 18 Python
Python对列表排序的方法实例分析
May 16 Python
python相似模块用例
Mar 04 Python
Python3 replace()函数使用方法
Mar 19 Python
PyQT实现多窗口切换
Apr 20 Python
python中pika模块问题的深入探究
Oct 13 Python
Python3 pip3 list 出现 DEPRECATION 警告的解决方法
Feb 16 Python
Pyqt QImage 与 np array 转换方法
Jun 27 Python
关于Python3 类方法、静态方法新解
Aug 30 Python
Django数据结果集序列化并展示实现过程
Apr 22 Python
Pandas中DataFrame基本函数整理(小结)
Jul 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
浅析PHP程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
PHP中ini_set和ini_get函数的用法小结
2014/02/18 PHP
PHP响应post请求上传文件的方法
2015/12/17 PHP
PHP操作MySQL中BLOB字段的方法示例【存储文本与图片】
2017/09/15 PHP
在laravel框架中实现封装公共方法全局调用
2019/10/14 PHP
jQuery版Tab标签切换
2011/03/16 Javascript
JQuery扩展插件Validate 5添加自定义验证方法
2011/09/05 Javascript
JS图片无缝、平滑滚动代码
2014/03/11 Javascript
JavaScript中最简洁的编码html字符串的方法
2014/10/11 Javascript
JavaScript中String.match()方法的使用详解
2015/06/06 Javascript
JavaScript获取并更改input标签name属性的方法
2015/07/02 Javascript
jQuery实现鼠标经过事件的延时处理效果
2020/08/20 Javascript
canvas实现图像放大镜
2017/02/06 Javascript
JS继承定义与使用方法简单示例
2020/02/19 Javascript
JS操作Fckeditor的一些常用方法(获取、插入等)
2020/02/19 Javascript
解决echarts vue数据更新,视图不更新问题(echarts嵌在vue弹框中)
2020/07/20 Javascript
django自定义Field实现一个字段存储以逗号分隔的字符串
2014/04/27 Python
python实现超市扫码仪计费
2018/05/30 Python
详解python函数的闭包问题(内部函数与外部函数详述)
2019/05/17 Python
python3中利用filter函数输出小于某个数的所有回文数实例
2019/11/24 Python
python+adb命令实现自动刷视频脚本案例
2020/04/23 Python
keras Lambda自定义层实现数据的切片方式,Lambda传参数
2020/06/11 Python
python性能测试工具locust的使用
2020/12/28 Python
Ted Baker英国官网:男士和女士服装及配件
2017/03/13 全球购物
Harman Audio官方商店:购买JBL、Harman Kardon、Infinity和AKG
2019/12/05 全球购物
在C语言中"指针和数组等价"到底是什么意思?
2014/03/24 面试题
培训研修方案
2014/06/06 职场文书
酒店周年庆活动方案
2014/08/21 职场文书
后勤管理员岗位职责
2014/08/27 职场文书
2014流动人口计划生育工作总结
2014/12/20 职场文书
销售员自我评价
2015/03/11 职场文书
工程技术员岗位职责
2015/04/11 职场文书
故意杀人案辩护词
2015/05/21 职场文书
对象析构函数__del__在Python中何时使用
2022/03/22 Python
星际争霸:毕姥爷vs解冻03
2022/04/01 星际争霸
Win11 BitLocker 驱动器加密
2022/04/19 数码科技