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数据结构树和二叉树简介
Apr 29 Python
python通过urllib2获取带有中文参数url内容的方法
Mar 13 Python
Python中的异常处理简明介绍
Apr 13 Python
python实现根据ip地址反向查找主机名称的方法
Apr 29 Python
在Python的Tornado框架中实现简单的在线代理的教程
May 02 Python
12步教你理解Python装饰器
Feb 25 Python
python编写暴力破解zip文档程序的实例讲解
Apr 24 Python
对python 命令的-u参数详解
Dec 03 Python
python实现统计文本中单词出现的频率详解
May 20 Python
django连接oracle时setting 配置方法
Aug 29 Python
Python使用docx模块实现刷题功能代码
Feb 13 Python
python实现FTP循环上传文件
Mar 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
做个自己站内搜索引擎
2006/10/09 PHP
GD输出汉字的函数的分析
2006/10/09 PHP
资料注册后发信小技巧
2006/10/09 PHP
php 在文件指定行插入数据的代码
2010/05/08 PHP
PHP 枚举类型的管理与设计知识点总结
2020/02/13 PHP
将CKfinder整合进CKEditor3.0的新方法
2010/01/10 Javascript
javascript hasFocus使用实例
2010/06/29 Javascript
js通过googleAIP翻译PHP系统的语言配置的实现代码
2011/10/17 Javascript
自己动手实现jQuery Callbacks完整功能代码详解
2013/11/25 Javascript
jquery选择符快速提取web表单数据示例
2014/03/27 Javascript
jQuery中cookie插件用法实例分析
2015/12/04 Javascript
JS库之wow.js使用方法
2017/09/14 Javascript
vue获取DOM元素并设置属性的两种实现方法
2017/09/30 Javascript
使用JS中的Replace()方法遇到的问题小结
2017/10/20 Javascript
Vue js 的生命周期(看了就懂)(推荐)
2019/03/29 Javascript
解决Vue项目打包后打开index.html页面显示空白以及图片路径错误的问题
2019/10/25 Javascript
[01:20:06]TNC vs VG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
[06:45]DOTA2-DPC中国联赛 正赛 Magma vs LBZS 选手采访
2021/03/11 DOTA
python网络爬虫采集联想词示例
2014/02/11 Python
详解Python中用于计算指数的exp()方法
2015/05/14 Python
Python的Flask框架中集成CKeditor富文本编辑器的教程
2016/06/13 Python
教你用python3根据关键词爬取百度百科的内容
2016/08/18 Python
python调用Delphi写的Dll代码示例
2017/12/05 Python
Python设计模式之门面模式简单示例
2018/01/09 Python
详解python 注释、变量、类型
2018/08/10 Python
pycharm激活码快速激活及使用步骤
2020/03/12 Python
Django URL参数Template反向解析
2020/11/24 Python
python 使用cycle构造无限循环迭代器
2020/12/02 Python
css3中background新增的4个新的相关属性用法介绍
2013/09/26 HTML / CSS
Vans英国官方网站:美国南加州的原创极限运动潮牌
2017/01/20 全球购物
触发器(trigger)的功能都有哪些?写出一个触发器的例子
2012/09/17 面试题
个人公开承诺书
2014/03/28 职场文书
2014年小学教师工作总结
2014/11/10 职场文书
通知范文怎么写
2015/04/16 职场文书
聋哑人盗窃罪辩护词
2015/05/21 职场文书
Python异常类型以及处理方法汇总
2021/06/05 Python