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实现将文件树中所有文件和子目录归档到tar压缩文件的方法
May 22 Python
简单总结Python中序列与字典的相同和不同之处
Jan 19 Python
用Python实现随机森林算法的示例
Aug 24 Python
Python实现矩阵加法和乘法的方法分析
Dec 19 Python
python实现对文件中图片生成带标签的txt文件方法
Apr 27 Python
Python 找到列表中满足某些条件的元素方法
Jun 26 Python
Python分割指定页数的pdf文件方法
Oct 26 Python
python实现小世界网络生成
Nov 21 Python
通过实例解析python创建进程常用方法
Jun 19 Python
基于CentOS搭建Python Django环境过程解析
Aug 24 Python
Python用摘要算法生成token及检验token的示例代码
Dec 01 Python
Python中tqdm的使用和例子
Sep 23 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 采集书并合成txt格式的实现代码
2009/03/01 PHP
php5.3中连接sqlserver2000的两种方法(com与ODBC)
2012/12/29 PHP
php获取服务器信息的实现代码
2013/02/04 PHP
PHP自动识别当前使用移动终端
2018/05/21 PHP
PHP超低内存遍历目录文件和读取超大文件的方法
2019/05/01 PHP
Javascript 学习书 推荐
2009/06/13 Javascript
为jQuery增加join方法的实现代码
2010/11/28 Javascript
基于Jquery的$.cookie()实现跨越页面tabs导航实现代码
2011/03/03 Javascript
JavaScript数据类型之基本类型和引用类型的值
2015/04/01 Javascript
JS简单实现多级Select联动菜单效果代码
2015/09/06 Javascript
理解JS绑定事件
2016/01/19 Javascript
很实用的js选项卡切换效果
2016/08/12 Javascript
JS复制对应id的内容到粘贴板(Ctrl+C效果)
2017/01/23 Javascript
分享一个精简的vue.js 图片lazyload插件实例
2017/03/13 Javascript
除Console.log()外更多的Javascript调试命令
2018/01/24 Javascript
通过jquery toggleClass()属性制作文章段落更改背景颜色
2018/05/21 jQuery
js实现轮播图的完整代码
2020/10/26 Javascript
JS实现获取数组中最大值或最小值功能示例
2019/03/02 Javascript
vue实现表格过滤功能
2019/09/27 Javascript
Vue两种组件类型:递归组件和动态组件的用法
2020/08/06 Javascript
Python中用startswith()函数判断字符串开头的教程
2015/04/07 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
基于Python中的yield表达式介绍
2019/11/19 Python
PyCharm使用Docker镜像搭建Python开发环境
2019/12/26 Python
Pytorch 实现数据集自定义读取
2020/01/18 Python
python itsdangerous模块的具体使用方法
2020/02/17 Python
html5 外链式实现加减乘除的代码
2019/09/04 HTML / CSS
美国户外烹饪产品购物网站:Outdoor Cooking
2020/01/10 全球购物
全球异乡人的跨境社交电商平台:Kouhigh口嗨网
2020/07/24 全球购物
模具专业毕业生自荐书范文
2014/02/19 职场文书
疾病捐款倡议书
2014/05/13 职场文书
关于运动会广播稿200字
2014/10/08 职场文书
2015民办小学年度工作总结
2015/05/26 职场文书
python绘图subplots函数使用模板的示例代码
2021/04/30 Python
springboot中的pom文件 project报错问题
2022/01/18 Java/Android
Python语法学习之进程的创建与常用方法详解
2022/04/08 Python