NSRecursiveLock递归锁的使用

企业动态
NSRecursiveLock实际上定义的是一个递归锁,这个锁可以被同一线程多次请求,而不会引起死锁。这主要是用在循环或递归操作中。我们先来看一个示例:

NSRecursiveLock递归锁的使用

NSRecursiveLock实际上定义的是一个递归锁,这个锁可以被同一线程多次请求,而不会引起死锁。这主要是用在循环或递归操作中。我们先来看一个示例:

  1. NSLock *lock = [[NSLock alloc] init]; 
  2.  
  3. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
  4.  
  5. static void (^RecursiveMethod)(int); 
  6.  
  7. RecursiveMethod = ^(int value) { 
  8.  
  9. [lock lock]; 
  10. if (value > 0) { 
  11.  
  12. NSLog(@"value = %d", value); 
  13. sleep(2); 
  14. RecursiveMethod(value - 1); 
  15. [lock unlock]; 
  16. }; 
  17.  
  18. RecursiveMethod(5); 
  19. });

这段代码是一个典型的死锁情况。在我们的线程中,RecursiveMethod是递归调用的。所以每次进入这个block时,都会去加一次锁,而从第二次开始,由于锁已经被使用了且没有解锁,所以它需要等待锁被解除,这样就导致了死锁,线程被阻塞住了。调试器中会输出如下信息:

  1. value = 5 
  2. *** -[NSLock lock]: deadlock (<NSLock: 0x1700ceee0'(null)') *** Break on _NSLockError() to debug.  

在这种情况下,我们就可以使用NSRecursiveLock。它可以允许同一线程多次加锁,而不会造成死锁。递归锁会跟踪它被lock的次数。每次成功的lock都必须平衡调用unlock操作。只有所有达到这种平衡,锁***才能被释放,以供其它线程使用。

所以,对上面的代码进行一下改造,

NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];

这样,程序就能正常运行了,其输出如下所示:

  1. value = 5 
  2. value = 4 
  3. value = 3 
  4. value = 2 
  5. value = 1 

NSRecursiveLock除了实现NSLocking协议的方法外,还提供了两个方法,分别如下:

  1. // 在给定的时间之前去尝试请求一个锁 
  2. - (BOOL)lockBeforeDate:(NSDate *)limit 
  3.  
  4. // 尝试去请求一个锁,并会立即返回一个布尔值,表示尝试是否成功 
  5. - (BOOL)tryLock 
  6.  
  7. 这两个方法都可以用于在多线程的情况下,去尝试请求一个递归锁,然后根据返回的布尔值,来做相应的处理。如下代码所示: 
  8.  
  9. NSRecursiveLock *lock = [[NSRecursiveLock alloc] init]; 
  10.  
  11. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
  12.  
  13. static void (^RecursiveMethod)(int); 
  14.  
  15. RecursiveMethod = ^(int value) { 
  16.  
  17. [lock lock]; 
  18. if (value > 0) { 
  19.  
  20. NSLog(@"value = %d", value); 
  21. sleep(2); 
  22. RecursiveMethod(value - 1); 
  23. [lock unlock]; 
  24. }; 
  25.  
  26. RecursiveMethod(5); 
  27. }); 
  28.  
  29. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
  30.  
  31. sleep(2); 
  32. BOOL flag = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; 
  33. if (flag) { 
  34. NSLog(@"lock before date"); 
  35.  
  36. [lock unlock]; 
  37. else { 
  38. NSLog(@"fail to lock before date"); 
  39. });

在前面的代码中,我们又添加了一段代码,增加一个线程来获取递归锁。我们在第二个线程中尝试去获取递归锁,当然这种情况下是会失败的,输出结果如下:

  1. value = 5 
  2. value = 4 
  3. fail to lock before date 
  4. value = 3 
  5. value = 2 
  6. value = 1 

另外,NSRecursiveLock还声明了一个name属性,如下:

@property(copy) NSString *name

我们可以使用这个字符串来标识一个锁。Cocoa也会使用这个name作为错误描述信息的一部分。

 

参考

 

NSRecursiveLock Class Reference

 

责任编辑:chenqingxiang 来源: 南峰子的技术博客
相关推荐

2024-01-29 01:08:01

悲观锁递归锁读写锁

2009-09-02 18:44:19

C#递归

2010-09-25 15:20:43

SQL递归语句

2024-01-30 07:36:51

Javalocks

2013-08-20 09:23:06

Scala递归

2023-01-06 09:40:20

项目性能

2020-07-10 08:15:19

递归算法函数

2022-06-15 07:32:35

Lock线程Java

2009-06-06 19:17:37

java递归删除

2013-04-10 10:58:19

LambdaC#

2023-11-10 16:04:46

递归图Python

2009-11-17 16:16:59

PHP递归函数

2009-08-31 17:11:37

Lambda表达式

2024-02-29 09:44:36

Java工具

2018-07-31 10:10:06

MySQLInnoDB死锁

2010-01-21 17:31:15

VB.NET递归过程

2010-03-05 09:40:08

Python递归

2010-10-27 15:11:52

oracle递归查询

2021-12-27 10:13:51

Goatomic数据竞争

2010-04-02 15:04:14

Oracle递归查询
点赞
收藏

51CTO技术栈公众号