day9-递归锁(RLock)

产生背景

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

import threading,time


def run1():
    print("grab the first part data")
    lock.acquire()  #加锁(第一个小门)
    global num
    num += 1
    lock.release()  #释放锁(第一个小门)
    return num


def run2():
    print("grab the second part data")
    lock.acquire()  #加锁(第二个小门)
    global num2
    num2 += 1
    lock.release()  #释放锁(第二个小门)
    return num2


def run3():
    lock.acquire()  #加锁(第一个大门)
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release() #释放锁(第一个大门)
    print(res, res2)


num, num2 = 0, 0
lock = threading.Lock()
for i in range(10): #生成10个线程,每个线程都启动run3函数
    t = threading.Thread(target=run3)
    t.start()

while threading.active_count() != 1: #等所有线程执行完毕(最终只有一个主线程) 相当于for t in t_obj:t.join()
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)

#输出

11
11
11
11
11
11
。
。
。
死循环

解析:按照程序自上而下执行,2个小门中的锁在同一时间应该只有一把加锁,但是在程序执行后,出现了死循环,这是为什么呢?同时我们对程序进行修改将run3中的res2=run2注释掉,同样会出现死循环。打印出11是程序运行10个线程都没有退出锁+主线程要等待子线程结束,所以总数为11,处于卡死状态。

因为run3函数和run1函数都获取了同一个锁,而run3函数又会调用run1函数。如果lock锁是个非递归锁,则这个程序就会立即死锁。因此在为一段程序加锁时要格外小心,否则很容易因为这种调用关系而造成死锁。

解决方案:这种情况下,就可以使用递归锁。

递归锁

说明:在Python中为了支持同一个线程中多次请求同一资源,Python提供了可重入锁,这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release。其他的线程才能获取资源。

#非递归锁
lock = threading.Lock()  
--------------------程序修改为---------------------------------------
for i in range(2): #生成2个线程,每个线程都启动run3函数(便于分析结果)
#递归锁
lock = threading.RLock()  #生成递归锁实例

#程序运行递归锁输出

grab the first part data
--------between run1 and run2-----
grab the second part data
1 1
grab the first part data
--------between run1 and run2-----
grab the second part data
2 2
----all threads done---
2 2

Process finished with exit code 0

 

posted @ 2017-11-15 15:40  Mr.hu  阅读(158)  评论(0编辑  收藏  举报