我们知道递归就是自己调用自己即一个方法内部又调用了这个方法本身。那么什么是递归锁呢?
递归锁
递归锁是应用在递归调用中的,它可以防止在递归调用中使用普通锁造成的死锁。
在介绍递归锁之前先演示一下普通锁在递归调用中的问题,看代码:
- (void)test{
pthread_mutex_lock(&_mutex);
NSLog(@"%s", __func__);
static int num = 0;
if (num < 10) {
num ++;
[self test];
}
pthread_mutex_unlock(&_mutex);
}
我们这篇文章中介绍锁是pthread_mutex_t,它的初始化方法如下:
- (void)__initMutex:(pthread_mutex_t *)mutex
{
// 递归锁:允许同一个线程对一把锁进行重复加锁
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
// 初始化锁
pthread_mutex_init(mutex, &attr);
// 销毁属性
pthread_mutexattr_destroy(&attr);
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor greenColor];
[self __initMutex:&_mutex];
}
其中的PTHREAD_MUTEX_NORMAL代表它是一把普通的锁。看打印结果:
6.pthread_mutex_t[1253:28817] -[ViewController test]
6.pthread_mutex_t[1253:28861] XPC connection interrupted
test方法只被调用了一次,和我们预期的并不一样,这是为什么呢?
死锁
在递归调用中使用普通的锁,出现了死锁。为什么会出现死锁呢?我们分析一下。
第一次调用test方法的时候,我们进行了加锁,在解锁之前我们又调用了test方法。第二次调用test方法的时候本来要对同一把锁进行加锁,可发现这把锁已经被加锁了,于是线程进入了休眠(pthread_mutex_t是一把互斥锁)等待解锁。线程休眠无法继续往下执行第一次加锁无法解锁于是就造成了死锁。
使用递归锁
在初始化锁的时候我们使用递归锁,
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
使用递归锁之后,打印结果就完全没问题了。
为什么使用递归锁就能防止死锁呢?这是因为递归锁能够对同一把锁重复加锁。
问:如果多个线程同时调用test方法,那递归锁岂不是不能保证线程的安全?
答:递归锁只允许同一个线程对同一把锁进行重复加锁。
注意:在使用pthread_mutex_t结束之后要进行销毁。
- (void)dealloc{
pthread_mutex_destroy(&_mutex);
}