python多线程互斥锁与死锁问题详解

 更新时间:2022年01月27日 15:58:58   作者:陈小c  
大家好,本篇文章主要讲的是python多线程互斥锁与死锁问题详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

一、多线程共享全局变量

代码实现的功能:

创建work01与worker02函数,对全局变量进行加一操作创建main函数,生成两个线程,同时调用两个函数

代码如下:

import threading

result = 0  # 定义全局变量result
def work1(num):
    global result
    for i in range(num):
        result += 1
    print('------from work1-------', result)


def work2(num):
    global result
    for i in range(num):
        result += 1
    print('------from work2-------', result)


def main():
    print('--------begin--------', result)
    # 创建两个线程
    t1 = threading.Thread(target=work1, args=(1000,))
    t2 = threading.Thread(target=work1, args=(1000,))
    t1.start()
    t2.start()

if __name__ == '__main__':
    main()

运行结果:

--------begin---------- 0
------from work1------- 1000
------from work1------- 2000

两个线程之间共享了全局变量result,但是当我们把range的数值调大一些,

    t1 = threading.Thread(target=work1, args=(1000000,))
    t2 = threading.Thread(target=work1, args=(1000000,))

我们再来看一下结果,这是为什么呢,我们往下看一下结果:

--------begin---------- 0
------from work1------- 1358452
------from work1------- 1696352

总结:
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

二、给线程加一把锁锁

假如当前 g_num 值是100,当线程1执行第一步时,cpu通过计算获得结果101,并准备把计算的结果101赋值给g_num,然后再传值的过程中,线程2突然开始执行了并且执行了第一步,此时g_num的值仍未100,101还在传递的过程中,还没成功赋值,线程2获得计算结果101,并准备传递给g_num,经过一来一去这么一折腾,分明做了两次加 1 操作,g_num结果却是101,误差就由此产生,往往循环次数越多,产生的误差就越大,此时我们可以加一把锁。

acquire() — 锁定资源,此时资源是锁定状态,其他线程无法修改锁定的资源,直到等待锁定的资源释放之后才能操作;

release() — 释放资源,也称为解锁操作,对锁定的资源解锁,解锁之后其他线程可以对资源正常操作;

以上面的代码为列子:想得到正确的结果,可以直接利用互斥锁在全局变量 加1 之前 锁定资源,然后在计算完成之后释放资源,这样就是一个完整的计算过程,至于应该是哪个线程先执行,无所谓,先到先得,凭本事说话….演示代码如下:

# 开发时间:2022-01-27 12:59
import threading

result = 0  # 定义全局变量result
mutex = threading.Lock()

def work1(num):
    global result
    mutex.acquire()
    for i in range(num):
        result += 1
    print('------from work1-------', result)
    mutex.release()


def work2(num):
    global result
    mutex.acquire()
    for i in range(num):
        result += 1
    print('------from work2-------', result)
    mutex.release()


def main():
    print('--------begin----------', result)
    # 创建两个线程
    t1 = threading.Thread(target=work1, args=(100000000,))
    t2 = threading.Thread(target=work1, args=(100000000,))
    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

我们来看一下结果:

--------begin---------- 0
------from work1------- 100000000
------from work1------- 200000000

三、死锁问题

1.单个互斥锁的死锁:

acquire()/release() 是成对出现的,互斥锁对资源锁定之后就一定要解锁,否则资源会一直处于锁定状态,其他线程无法修改;就好比上面的代码,任何一个线程没有释放资源release(),程序就会一直处于阻塞状态(在等待资源被释放),不信你可以试一试~

2.多个互斥锁的死锁:

在同时操作多个互斥锁的时候一定要格外小心,因为一不小心就容易进入死循环,假如有这样一个场景:boss让程序员一实现功能一的开发,让程序员二实现功能二的开发,功能开发完成之后一起整合代码!

# 导入线程threading模块
import threading
# 导入线程time模块
import time

# 创建互斥锁
mutex_one = threading.Lock()
mutex_two = threading.Lock()


def programmer_thread1():
    mutex_one.acquire()
    print("我是程序员1,module1开发正式开始,程序一加锁,程序二加锁")
    time.sleep(2)

    # 此时会堵塞,因为这个mutex_two已经被线程programmer_thread2抢先上锁了,等待解锁
    mutex_two.acquire()
    print("等待程序员2通知我合并代码")
    mutex_two.release()
    print('程序员2开发完了,程序员1释放第二把锁')

    mutex_one.release()
    print('程序员1开发完了,程序员1释放第一把锁')


def programmer_thread2():
    mutex_two.acquire()
    print("我是程序员2,module2开发正式开始,程序二加锁,程序一加锁")
    time.sleep(2)
    # 此时会堵塞,因为这个mutex_one已经被线程programmer_thread1抢先上锁了,等待解锁
    #mutex_two.release()
    mutex_one.acquire()
    print("等待程序员1通知我合并代码")
    mutex_one.release()
    print('程序员2释放第一把锁')
   # mutex_two.release()
    print('程序员2释放第二把锁')


def main():
    t1 = threading.Thread(target=programmer_thread1)
    t2 = threading.Thread(target=programmer_thread2)

    # 启动线程
    t1.start()
    t2.start()
    # 阻塞函数,等待线程结束
    t1.join()
    t2.join()
    # 整合代码结束
    print("整合代码结束 ")


if __name__ == "__main__":
    main()

分析下上面代码:程序员1在等程序员2通知,程序员2在等程序员1通知,两个线程都陷入阻塞中,因为两个线程都在等待对方解锁,这就是死锁!所以在开发中对于死锁的问题还是需要多多注意!

总结

到此这篇关于python多线程互斥锁与死锁问题详解的文章就介绍到这了,更多相关python互斥锁与死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python中map函数的技巧分享

    Python中map函数的技巧分享

    在Python中,map()是一个内置函数,这篇文章将从基础的使用方法到高级的技巧,全面介绍Python中map()方法的使用,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-07-07
  • python write无法写入文件的解决方法

    python write无法写入文件的解决方法

    今天小编就为大家分享一篇python write无法写入文件的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-01-01
  • Python如何实现机器人聊天

    Python如何实现机器人聊天

    这篇文章主要介绍了Python如何实现机器人聊天,帮助大家更好的理解和学习python,感兴趣的朋友可以了解下
    2020-09-09
  • 利用Python实现自制文件搜索小工具

    利用Python实现自制文件搜索小工具

    当自己电脑文件很多还有点乱,不记得自己文件放哪里的时候,用电脑自带的搜索文件,这个等待时间可慢了。所以我们不如自己用python做一个搜索工具!犄角旮旯的文件都能一秒钟搜索出来的那种
    2022-09-09
  • python与pycharm有何区别

    python与pycharm有何区别

    在本篇文章里小编给大家整理了关于pycharm与python的区别相关内容,有需要的朋友们可以学习下。
    2020-07-07
  • K-近邻算法的python实现代码分享

    K-近邻算法的python实现代码分享

    这篇文章主要介绍了K-近邻算法的python实现代码分享,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Python基于Socket实现的简单聊天程序示例

    Python基于Socket实现的简单聊天程序示例

    这篇文章主要介绍了Python基于Socket实现的简单聊天程序,结合简单实例形式分析了Python聊天程序的客户端与服务器端相关实现技巧,需要的朋友可以参考下
    2017-08-08
  • Django 对IP访问频率进行限制的例子

    Django 对IP访问频率进行限制的例子

    今天小编就为大家分享一篇Django 对IP访问频率进行限制的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • 解决更改AUTH_USER_MODEL后出现的问题

    解决更改AUTH_USER_MODEL后出现的问题

    这篇文章主要介绍了解决更改AUTH_USER_MODEL后出现的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05
  • python创建ArcGIS shape文件的实现

    python创建ArcGIS shape文件的实现

    今天小编就为大家分享一篇python创建ArcGIS shape文件的实现,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12

最新评论