day31 死锁现象、递归锁以及信号量

死锁现象

死锁:指的是某个资源被占用后一直得不到释放,导致其他需要这个资源的线程或进程进入阻塞状态

情况一:对同一把互斥锁多次执行acquire方法,将导致死锁

from threading import Lock

l = Lock()
l.acquire()  
print('run....')  # 打印run....
l.acquire()
print('deadlock....')  # 出现死锁,不打印

解决方法:首先这样写没有意义,其次在加锁时加上超时l.acquire(timeout=10),超出时间后继续执行,线程不会卡死

情况二:一个共享资源要访问必须同时具备多把锁,但是这些锁被不同线程或进程所持有,就会导致线程或进程之间相互等待对方释放,从而导致进入阻塞状态

import time
from threading import Lock, Thread

A = Lock()
B = Lock()


class Mytask(Thread):
    def run(self):
        self.eat()
        self.sleep()

    def eat(self):
        A.acquire()
        time.sleep(1)
        print(f'{self.name} got A', time.ctime())
        B.acquire()
        print(f'{self.name} got B', time.ctime())
        B.release()
        A.release()

    def sleep(self):
        B.acquire()
        time.sleep(1)
        print(f'{self.name} got B', time.ctime())
        A.acquire()
        print(f'{self.name} got A', time.ctime())
        A.release()
        B.release()


for i in range(10):
    t = Mytask()
    t.start()
--------------------------------------------------------------------------
Thread-1 got A Sat Jul  6 20:37:47 2019
Thread-1 got B Sat Jul  6 20:37:47 2019
Thread-2 got A Sat Jul  6 20:37:48 2019  
Thread-1 got B Sat Jul  6 20:37:48 2019   
# 线程2抢到了A锁没抢到B锁,线程1抢到了B锁没抢到A锁。线程2等线程1释放B锁,线程1等线程2释放A锁,双方互相等待,造成死锁现象

解决方法:1.抢锁一定按照相同的顺序去抢,2.给抢锁加上超时,如果超时则放弃执行

递归锁

在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:

import time
from threading import RLock, Thread

R = RLock()


class Mytask(Thread):
    def run(self):
        self.eat()
        self.sleep()

    def eat(self):
        R.acquire()
        time.sleep(1)
        print(f'{self.name} got A', time.ctime())
        R.release()

    def sleep(self):
        R.acquire()
        time.sleep(1)
        print(f'{self.name} got B', time.ctime())
        R.release()

for i in range(10):
    t = Mytask()
    t.start()

与互斥锁的区别:多线程之间都有互斥的效果,不同在于递归锁可以对这个锁执行多次acquire

信号量

可以限制同时并发执行公共代码的线程数量,如果限制数量为1则与普通互斥锁没有区别。并不能用来解决安全问题,而是用来限制最大的并发量

from threading import Semaphore, currentThread, Thread


def task():
    s.acquire()
    print('hello world')
    time.sleep(2)
    s.release()


s = Semaphore(3)  # 限制线程的并发数,不设置默认为1
for i in range(10):
    t = Thread(target=task)
    t.start()
posted @ 2019-07-06 21:00  Never&say&die  阅读(229)  评论(0编辑  收藏  举报