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

多线程

同步锁(互斥锁)

解决什么问题?

同步锁解决什么问题?

多个线程操作同一个数据,可能会发生数据错乱的问题,因为一个线程拿到数据后,还没来得及对数据进行操作,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-1D
2
Thread-1D1
Thread-1D
0
Thread-1D1
Thread-1D
2
Thread-1D1
Thread-1D
0
Thread-2D1
Thread-2D
2
Thread-2D1
Thread-2D
0
Thread-2D1
Thread-2D
2
Thread-2D1
Thread-2D
0
Thread-4D1
Thread-4D
2
Thread-4D1
Thread-4D
0
Thread-4D1
Thread-4D
2
Thread-4D1
Thread-4D
0
Thread-3D1
Thread-3D
2
Thread-3D1
Thread-3D
0
Thread-5D1
Thread-5D
2
Thread-5D1
Thread-5D
0
Thread-5D1
Thread-5D
2
Thread-5D1
Thread-5D
0
Thread-3D1
Thread-3D
2
Thread-3D1
Thread-3D
0

posted @ 2019-09-01 17:33  zx125  阅读(343)  评论(0编辑  收藏  举报