python多线程编程3: 使用互斥锁同步线程

问题的提出

上一节的例子中,每个线程互相独立,相互之间没有任何关系。现在假设这样一个例子:有一个全局的计数num,每个线程获取这个全局的计数,根据num进行一些处理,然后将num加1。很容易写出这样的代码:

# encoding: UTF-8import threadingimport time  class MyThread(threading.Thread):    def run(self):        global num        time.sleep(1)        num = num+1        msg = self.name+' set num to '+str(num)        print msgnum = 0def test():    for i in range(5):        t = MyThread()        t.start()if __name__ == '__main__':    test()

登录后复制

但是运行结果是不正确的:

Thread-5 set num to 2

Thread-3 set num to 3

立即学习“Python免费学习笔记(深入)”;

Thread-2 set num to 5

Thread-1 set num to 5

Thread-4 set num to 4

问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。

互斥锁同步

上面的例子引出了多线程编程的最常见问题:数据共享。当多个线程都修改某一个共享数据的时候,需要进行同步控制。

线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

threading模块中定义了Lock类,可以方便的处理锁定:

#创建锁

mutex = threading.Lock()

#锁定

mutex.acquire([timeout])

#释放

mutex.release()

其中,锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。

使用互斥锁实现上面的例子的代码如下:

import threadingimport time  class MyThread(threading.Thread):    def run(self):        global num        time.sleep(1)          if mutex.acquire(1):             num = num+1            msg = self.name+' set num to '+str(num)            print msg            mutex.release()num = 0mutex = threading.Lock()def test():    for i in range(5):        t = MyThread()        t.start()if __name__ == '__main__':    test()

登录后复制

运行结果:

Thread-3 set num to 1

Thread-4 set num to 2

Thread-5 set num to 3

Thread-2 set num to 4

Thread-1 set num to 5

可以看到,加入互斥锁后,运行结果与预期相符。

同步阻塞

当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”(参见多线程的基本概念)。

直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

互斥锁最基本的内容就是这些,下一节将讨论可重入锁(RLock)和死锁问题。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2284490.html

(0)
上一篇 2025年2月27日 20:46:36
下一篇 2025年2月23日 05:07:01

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Python多线程抓取Google搜索链接网页

    1)urllib2+beautifulsoup抓取goolge搜索链接 近期,参与的项目需要对Google搜索结果进行处理,之前学习了Python处理网页相关的工具。实际应用中,使用了urllib2和beautifulsoup来进行网页的抓…

    2025年2月27日
    200
  • python多线程编程2

    如上一节,python的threading.thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过thread类的start方法,可以启动该线程,交给python虚拟机进行调度,…

    编程技术 2025年2月27日
    200
  • python多线程编程1

    多线程编程必须理解的一些基本概念,适用于所有编程语言。内容: 并发式编程 多任务操作系统 多线程vs多进程 线程安全 立即学习“Python免费学习笔记(深入)”; 线程的生命周期 线程的类型 并发式编程 不同的编程范式对软件有不同的视角。…

    编程技术 2025年2月27日
    200
  • 使用Python读取和写入mp3文件的id3v1信息

    1.起因 一直以来疯迷“冬吴相对论”,为了整理下载他的MP3花了不少功夫,今天突然发现将电脑中的mp3导入到itunes后,文件名竟然不识别了。#_* itunes自动识别了mp3的信息内容。多次一举么,文件名挺好。事实如此,让我深感不完美…

    编程技术 2025年2月27日
    200
  • Python连接Redis连接配置

    系统环境: OS:Oracle Linux Enterprise 5.6 redis:redis-2.6.8 python:Python-2.7.3 redis的python包版本:redis-2.7.2.tar 立即学习“Python免费…

    编程技术 2025年2月27日
    200
  • Python 支持重启的异步 IO

    摘要 这是一份从Python3.3开始的Python3异步I/O提议。研究从PEP 3153缺失的具体提议。 这提议包括了一个可插入式的事件循环API,传输和与Twisted相似的协议抽象,以及来自(PEP 380) 基于yield的更高级…

    编程技术 2025年2月27日
    200
  • python发送邮件实例 – 使用smtplib模块

    # 导入 smtplib 和 MIMETextimport smtplibfrom email.mime.text import MIMEText    # 定义发送列表mailto_list=[“root@pythontab.com”,”…

    编程技术 2025年2月27日
    200
  • 用Python备份MYSQL 数据库

    工作需要,对公司的mysql数据库进行备份,赶上刚刚开始学python,看了一套简单的python教学视频,简单的写了个备份脚本,个人表示 对python 的class 、function、build-in function 、私有变量、全…

    编程技术 2025年2月27日
    200
  • python读取和生成excel文件

    今天来看一下如何使用python处理excel文件,处理excel文件是在工作中经常用到的,python为我们考虑到了这一点,python中本身就自带csv模块。 1.用python读取csv文件: csv是逗号分隔符格式 一般我们用的ex…

    2025年2月27日
    100
  • 用python脚本监控并发量

    该脚本作用用于查询日志过去一分钟内的并发量,并发单位位1分钟,结果打印在标准输出中,可以配合一些软件实现日志的并发实时监控,比如zabbix。 #! /usr/local/bin/python3import sysimport reimpo…

    编程技术 2025年2月27日
    200

发表回复

登录后才能评论