多线程-同步锁 死锁 递归锁

悠悠 2023-06-02 10:46 39阅读 0赞

多线程

同步锁(互斥锁)

解决什么问题?

同步锁解决什么问题?

多个线程操作同一个数据,可能会发生数据错乱的问题,因为一个线程拿到数据后,还没来得及对数据进行操作,cpu就有可能去执行另外一个线程,另外一个线程拿到的则是之前线程没有处理完的数据,如下

  1. import threading
  2. import time
  3. count=20
  4. def zx():
  5. global count
  6. print(count)
  7. time.sleep(0.001)
  8. count-=1
  9. t_list=[]
  10. for t in range(20):
  11. t=threading.Thread(target=zx)
  12. t_list.append(t)
  13. t.start()
  14. for i in t_list:
  15. i.join()
  16. print(count)

20
20
20
20
20
20
18
18
18
15
15
15
13
11
11
8
8
8
6
6
0

解决方法

可以强制让cpu执行完一部分代码后,才能去调用其他线程,这样可以确保,其他线程拿到想要的正确数据,但是这一部分是串行的。

具体实现的过程

一.100个线程去抢GIL锁,即抢执行权限

二.肯定有一个线程先抢到GIL(暂且称为线程1),然后开始执行,一旦执行就会拿到lock.acquire()

三.极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL,然后开始运行,但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL

四.直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock,然后其他的线程再重复2 3 4的过程

  1. import threading
  2. import time
  3. count=20
  4. lock=threading.Lock()
  5. def zx():
  6. global count
  7. lock.acquire()
  8. print(count)
  9. time.sleep(0.001)
  10. count-=1
  11. lock.release()
  12. t_list=[]
  13. for t in range(20):
  14. t=threading.Thread(target=zx)
  15. t_list.append(t)
  16. t.start()
  17. for i in t_list:
  18. i.join()
  19. print(count)

20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0

死锁

所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

比如有两个线程,线程1拿到了A锁,但是他只有拿到B锁才能把A锁释放,线程2拿到了B锁,他要拿到A锁才能释放B锁,结果这两个线程就死掉了

  1. import threading
  2. import time
  3. class MyThreading(threading.Thread):
  4. def run(self):
  5. self.run1()
  6. self.run2()
  7. def run1(self):
  8. A.acquire()
  9. print(self.name+"拿到了锁A")
  10. B.acquire()
  11. print(self.name+"拿到了锁B")
  12. B.release()
  13. print(self.name+"释放了锁B")
  14. A.release()
  15. print(self.name+"释放了锁A")
  16. def run2(self):
  17. B.acquire()
  18. print(self.name+"拿到了锁B")
  19. time.sleep(2)
  20. A.acquire()
  21. print(self.name+"拿到了锁A")
  22. A.release()
  23. print(self.name+"释放了锁A")
  24. B.release()
  25. print(self.name+"释放了锁B")
  26. if __name__ == '__main__':
  27. A=threading.Lock()
  28. B=threading.Lock()
  29. for t in range(5):
  30. t=MyThreading()
  31. t.start()

Thread-1拿到了锁A
Thread-1拿到了锁B
Thread-1释放了锁B
Thread-1释放了锁A
Thread-1拿到了锁B
Thread-2拿到了锁A

如何解决死锁

使用递归锁

递归锁

相当于把一块用了很多锁的代码块,看做一个整体,当这个代码块所有的锁都释放了,才能被其他的方法或者线程拿到锁

递归锁的实现原理很简单,当加锁,递归锁的引用计数+1,解锁则-1.当引用计数为0,才能被其他线程或者方法拿到锁。

  1. import threading
  2. import time
  3. class MyThreading(threading.Thread):
  4. def run(self):
  5. self.run1()
  6. self.run2()
  7. def run1(self):
  8. D.acquire()
  9. print(self.name+"D==1")
  10. D.acquire()
  11. print(self.name+"D==2")
  12. D.release()
  13. print(self.name+"D==1")
  14. D.release()
  15. print(self.name+"D==0")
  16. def run2(self):
  17. D.acquire()
  18. print(self.name+"D==1")
  19. time.sleep(2)
  20. D.acquire()
  21. print(self.name+"D==2")
  22. D.release()
  23. print(self.name+"D==1")
  24. D.release()
  25. print(self.name+"D==0")
  26. if __name__ == '__main__':
  27. D=threading.RLock()
  28. for t in range(5):
  29. t=MyThreading()
  30. t.start()

这里的==被转义的,将就着看
Thread-1D==1
Thread-1D==2
Thread-1D==1
Thread-1D==0
Thread-1D==1
Thread-1D==2
Thread-1D==1
Thread-1D==0
Thread-2D==1
Thread-2D==2
Thread-2D==1
Thread-2D==0
Thread-2D==1
Thread-2D==2
Thread-2D==1
Thread-2D==0
Thread-4D==1
Thread-4D==2
Thread-4D==1
Thread-4D==0
Thread-4D==1
Thread-4D==2
Thread-4D==1
Thread-4D==0
Thread-3D==1
Thread-3D==2
Thread-3D==1
Thread-3D==0
Thread-5D==1
Thread-5D==2
Thread-5D==1
Thread-5D==0
Thread-5D==1
Thread-5D==2
Thread-5D==1
Thread-5D==0
Thread-3D==1
Thread-3D==2
Thread-3D==1
Thread-3D==0

转载于:https://www.cnblogs.com/zx125/p/11442945.html

发表评论

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

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

相关阅读

    相关 线-同步

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