Python-线程同步(锁)和死锁

偏执的太偏执、 2023-06-30 08:36 135阅读 0赞

线程同步

共享数据:

  • 如果多个线程共同对某个数据修改,可能出现不可预料的结果,为了保证数据的安全性,需要对多个线程进行同步,一个一个的完成,一个做完另一个才能进来。
  • 效率会降低。

多线程的优势在于可以同时运行多个任务,但是当线程需要共享数据时,可能存在数据不同步的问题。

为了避免这个问题,引入了的概念。

python对线程加锁主要有LockRlock模块

使用Tread对象LockRlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。


Lock模块

用例

  1. import threading
  2. from time import sleep
  3. lock = threading.Lock()
  4. list1 = [0] * 10
  5. def task1():
  6. # 获取线程锁,如果已经上锁,则等待锁的释放。
  7. lock.acquire() # 阻塞
  8. for i in range(len(list1)):
  9. list1[i] = 1
  10. sleep(0.5)
  11. lock.release()
  12. def task2():
  13. # 获取线程锁,如果已经上锁,则等待锁的释放。
  14. lock.acquire() # 阻塞
  15. for i in range(len(list1)):
  16. print("----->",list1[i])
  17. sleep(0.5)
  18. lock.release()
  19. if __name__ == '__main__':
  20. t1 = threading.Thread(target=task1)
  21. t2 = threading.Thread(target=task2)
  22. t2.start()
  23. t1.start()
  24. t2.join()
  25. t1.join()
  26. print(list1)

输出:

  1. -----> 0
  2. -----> 0
  3. -----> 0
  4. -----> 0
  5. -----> 0
  6. -----> 0
  7. -----> 0
  8. -----> 0
  9. -----> 0
  10. -----> 0
  11. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Lock有acquire()和release()方法,这两个方法必须是成对出现的,acquire()后面必须release()后才能再acquire(),否则会造成死锁


死锁

开发过程中使用线程,在线程间共享多个资源的时候,如果两个线程占有一部分资源并且同时等待对方的资源,就会造成死锁
尽管死锁很少发生,但是一旦放生就会造成应用停止响应,程序不做任何事情。

在这里插入图片描述

避免死锁

  • 重构代码
  • 使用timeout参数

    from threading import Thread,Lock
    from time import sleep

    lockA = Lock()
    lockB = Lock()

    class Mythread1(Thread):

    1. def run(self) -> None: # 执行start()方法自动寻找run()方法
    2. if lockA.acquire(): # 如果可以获取到锁,返回True
    3. print(self.name+'获取到A锁!')
    4. sleep(0.1)
    5. if lockB.acquire(timeout=1): # 阻塞,现在等待不到B锁,设定时间自动释放锁
    6. print(self.name+'又获取到了B锁!原来还有A锁!')
    7. lockB.release()
    8. lockA.release()

    class Mythread2(Thread):

    1. def run(self) -> None: # 执行start()方法自动寻找run()方法
    2. if lockB.acquire(): # 如果可以获取到锁,返回True
    3. print(self.name+'获取到B锁!')
    4. sleep(0.1)
    5. if lockA.acquire():
    6. print(self.name+'又获取到了A锁!原来还有B锁!')
    7. lockA.release()
    8. lockB.release()

    if name == ‘main‘:

    1. t1 = Mythread1()
    2. t2 = Mythread2()
    3. t1.start()
    4. t2.start()
    5. t1.join()
    6. t2.join()
    7. print('结束!!!!!!!!!!!!!')

输出:

  1. Thread-1获取到A锁!
  2. Thread-2获取到B锁!
  3. # 此处Thread-1等待B锁因为timeout=1等待1秒后,自动释放了
  4. Thread-2又获取到了A锁!原来还有B锁!
  5. 结束!!!!!!!!!!!!!

发表评论

表情:
评论列表 (有 0 条评论,135人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线-同步 递归

    多线程 同步锁(互斥锁) 解决什么问题? 同步锁解决什么问题? 多个线程操作同一个数据,可能会发生数据错乱的问题,因为一个线程拿到数据后,还没来得及对数据进行操