8、递归锁和死锁

线程死锁和递归锁

在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。

死锁示例

#!/usr/bin/env python

# -*- coding: utf-8 -*-

# @Time : 2018/4/14 11:07

# @Author : CaiChangEn

# @Email : [email protected]

# @Software: PyCharm

import threading,time

import time

class MyThread(threading.Thread):

def actionA(self):

A.acquire() # A获得锁

print(self.name,'GotA',time.ctime())

time.sleep(2)

B.acquire() # B获得锁

print(self.name, 'GotB', time.ctime())

time.sleep(1)

B.release() # 释放锁

A.release() # 释放锁

def actionB(self):

B.acquire() # B获得锁

print(self.name,'GotB',time.ctime())

time.sleep(2)

A.acquire() # A获得锁

print(self.name, 'GotA', time.ctime())

time.sleep(1)

A.release() # 释放锁

B.release() # 释放锁

def run(self):

self.actionA()

self.actionB()

if __name__ == '__main__':

# 创建两把锁

A=threading.Lock()

B=threading.Lock()

L=[]

for i in range(5):

t=MyThread()

t.start()

L.append(t)

for i in L:

i.join() # 主线程等待子线程结束之后再执行

print('ending...')

分析

当第一个线程进来的时候首先会进入到actionA获得A和B的锁,然后释放释放之后会有第二个线程启动,那么在线程启动的同时第一个线程会进入到actionB获得B的锁,那么此时的第二个线程会进入到actionA获得A的锁,进入到此时,问题就来了,第一个线程需要获得B锁,第二个线程火会需要获得A锁,那么此时就产生的锁竞争,继而引发死锁的产生

解决死锁的递归锁

解决方法,递归所,在Python中为了支持统一线程中多次请求同一资源,python提供了可重入锁RLock

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require,直到一个线程所有的acquire都被release,其他的线程才能获得资源;

二者的区别:递归锁可以连续acquire多次,互斥锁只能acquire一次

#!/usr/bin/env python

# -*- coding: utf-8 -*-

# @Time : 2018/4/14 11:07

# @Author : CaiChangEn

# @Email : [email protected]

# @Software: PyCharm

import threading,time

import time

class MyThread(threading.Thread):

def actionA(self):

r_lock.acquire() # A获得锁

print(self.name,'GotA',time.ctime())

time.sleep(2)

r_lock.acquire() # B获得锁

print(self.name, 'GotB', time.ctime())

time.sleep(1)

r_lock.release() # 释放锁

r_lock.release() # 释放锁

def actionB(self):

r_lock.acquire() # B获得锁

print(self.name,'GotB',time.ctime())

time.sleep(2)

r_lock.acquire() # A获得锁

print(self.name, 'GotA', time.ctime())

time.sleep(1)

r_lock.release() # 释放锁

r_lock.release() # 释放锁

def run(self):

self.actionA()

self.actionB()

if __name__ == '__main__':

# 创建两把锁

# A=threading.Lock()

# B=threading.Lock()

r_lock=threading.RLock() # 创建递归锁

L=[]

for i in range(5):

t=MyThread()

t.start()

L.append(t)

for i in L:

i.join() # 主线程等待子线程结束之后再执行

print('ending...')

分析

rlock是递归锁,拿我们现在这个例子来说,它们其实用的都是一把锁,就是在内部加了一个计数器,我们上面的例子获得了2把锁,那么此时的计数器应该大于0,当第一个线程进来的时候,会直接获得两把锁,执行完成actionA会释放两把锁,那么第一个线程此时就会进入到actionB那么这个过程中会启动第二个线程(主要看切换时间够不够),第二个线程又会执行actionA,那么此时第一个线程是等待的,因为递归锁的原理就是不管有多少个线程不管有多少个锁,如果一个人获得了锁,就声明了其他人也不可以获得其他的锁 ;

  • 注意: 一个线程内部可以维护多个锁,只要第一个线程获得一把锁,那就意味着其他线程是进不来的,在这么一个时刻只有一个线程能够被执行,其他线程一直是等待锁释放的状态,这就保证了这把锁,一直是一个锁在使用


分享到:


相關文章: