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


    多线程

    同步锁(互斥锁)

    解决什么问题?

    同步锁解决什么问题?

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

  • 相关阅读:
    驱动
    设备编号
    makefile 中的赋值
    UART
    c 语言的复杂声明
    linux下arm汇编的常用指令解析
    linux下的arm汇编程序
    ok6410下的uboot分析与实现
    层级选择器的理解
    css外部样式的理解
  • 原文地址:https://www.cnblogs.com/zx125/p/11442945.html
Copyright © 2020-2023  润新知