多线程-同步锁 死锁 递归锁
多线程
同步锁(互斥锁)
解决什么问题?
同步锁解决什么问题?
多个线程操作同一个数据,可能会发生数据错乱的问题,因为一个线程拿到数据后,还没来得及对数据进行操作,cpu就有可能去执行另外一个线程,另外一个线程拿到的则是之前线程没有处理完的数据,如下
import threading
import time
count=20
def zx():
global count
print(count)
time.sleep(0.001)
count-=1
t_list=[]
for t in range(20):
t=threading.Thread(target=zx)
t_list.append(t)
t.start()
for i in t_list:
i.join()
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的过程
import threading
import time
count=20
lock=threading.Lock()
def zx():
global count
lock.acquire()
print(count)
time.sleep(0.001)
count-=1
lock.release()
t_list=[]
for t in range(20):
t=threading.Thread(target=zx)
t_list.append(t)
t.start()
for i in t_list:
i.join()
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锁,结果这两个线程就死掉了
import threading
import time
class MyThreading(threading.Thread):
def run(self):
self.run1()
self.run2()
def run1(self):
A.acquire()
print(self.name+"拿到了锁A")
B.acquire()
print(self.name+"拿到了锁B")
B.release()
print(self.name+"释放了锁B")
A.release()
print(self.name+"释放了锁A")
def run2(self):
B.acquire()
print(self.name+"拿到了锁B")
time.sleep(2)
A.acquire()
print(self.name+"拿到了锁A")
A.release()
print(self.name+"释放了锁A")
B.release()
print(self.name+"释放了锁B")
if __name__ == '__main__':
A=threading.Lock()
B=threading.Lock()
for t in range(5):
t=MyThreading()
t.start()
Thread-1拿到了锁A
Thread-1拿到了锁B
Thread-1释放了锁B
Thread-1释放了锁A
Thread-1拿到了锁B
Thread-2拿到了锁A
如何解决死锁
使用递归锁
递归锁
相当于把一块用了很多锁的代码块,看做一个整体,当这个代码块所有的锁都释放了,才能被其他的方法或者线程拿到锁
递归锁的实现原理很简单,当加锁,递归锁的引用计数+1,解锁则-1.当引用计数为0,才能被其他线程或者方法拿到锁。
import threading
import time
class MyThreading(threading.Thread):
def run(self):
self.run1()
self.run2()
def run1(self):
D.acquire()
print(self.name+"D==1")
D.acquire()
print(self.name+"D==2")
D.release()
print(self.name+"D==1")
D.release()
print(self.name+"D==0")
def run2(self):
D.acquire()
print(self.name+"D==1")
time.sleep(2)
D.acquire()
print(self.name+"D==2")
D.release()
print(self.name+"D==1")
D.release()
print(self.name+"D==0")
if __name__ == '__main__':
D=threading.RLock()
for t in range(5):
t=MyThreading()
t.start()
这里的==被转义的,将就着看
Thread-1D1
Thread-1D2
Thread-1D1
Thread-1D0
Thread-1D1
Thread-1D2
Thread-1D1
Thread-1D0
Thread-2D1
Thread-2D2
Thread-2D1
Thread-2D0
Thread-2D1
Thread-2D2
Thread-2D1
Thread-2D0
Thread-4D1
Thread-4D2
Thread-4D1
Thread-4D0
Thread-4D1
Thread-4D2
Thread-4D1
Thread-4D0
Thread-3D1
Thread-3D2
Thread-3D1
Thread-3D0
Thread-5D1
Thread-5D2
Thread-5D1
Thread-5D0
Thread-5D1
Thread-5D2
Thread-5D1
Thread-5D0
Thread-3D1
Thread-3D2
Thread-3D1
Thread-3D0