NSLock 解读

上一篇大概介绍了一下锁的分类

这篇我们就解读一下第一个锁 NSLock

NSLock是Foundation提供的类,NSLock的API很少也很简单。常用的就几个方法

备注:深入解读 NSLock则需要 Foundation 源码, 但是这里公开的Foundation框架中只有NSObject的实现。假如我们想要查看NSString,NSArray,NSRunLoop,NSThread等Foundation这些类,是没有源码的。虽然通过汇编语言,一步步的跟踪也可以查看。但是汇编太过于晦涩难懂,所以这里推荐一个GNUstep

GNUstep是GUN计划的项目之一,它将Cocoa的OC库重新开源实现了一遍,并且开源出来了。虽然GNUstep不是苹果官方的源码,是GNU计划写的,但是还是具有一定参考价值的。

GNUstep源码下载地址:http://www.gnustep.org/resources/downloads.php

一. NSLock 互斥锁 不能多次调用 lock方法,会造成死锁 ,遵循 NSLocking 协议。进行加锁、解锁

@protocol NSLocking

(void)lock;//加锁

(void)unlock;//解锁

@end

NSLock实现了NSLocking协议:

@interface NSLock : NSObject {

@private

void *_priv;

}

// 尝试获取锁,获取到返回YES,获取不到返回NO

(BOOL)tryLock;

// 在指定时间点之前获取锁,能够获取返回YES,获取不到返回NO

(BOOL)lockBeforeDate:(NSDate *)limit;

// 锁名称,如果使用锁出现异常,输出的log中会有

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end

-tryLock:如果能获取到锁返回YES,如果获取不到锁返回NO,但不会使线程进入休眠,会继续向下执行

-lockBeforeDate::如果锁已被锁定,在指定的时间点之前线程进入休眠等待锁释放。如果在时间点之前锁被释放了,线程立即被唤醒获得锁,该函数会返回YES,继续执行任务,不会一直休眠等到那个时间点。如果等到时间点还没有获得锁会返回NO,并继续执行任务

NSLock是非递归锁,不能重入,否则会发生死锁:

上代码~~~

可以看到上面的代码最终只打印了testLock1,其他的几个打印不会去执行。因为 testLock1被锁了之后,还没有调用解锁就执行了testLock2。这个时候去lock 但是锁获取不到就休眠等待,直到testLock1 unlock解锁之后才会继续执行,但是这个时候testLock2 不执行完, testLock1 里面的代码也就被卡着不能继续。

注意:

-lock和-unlock必须在相同的线程调用,也就是说,他们必须在同一个线程中成对调用,否则会产生未知结果。

官方文档原文:Unlocking a lock from a different thread can result in undefined behavior.

可以阅读 GNUstep 的 Foundation (参考),也可以自行下载 swift 版本的 Foundation 源码分析


通过源码可知验证 NSLock 是对 pthread 中互斥锁 的封装。

其他都好理解,这里列一下 timedLock() 的实现流程:

1、设定超时时间,进入while循环。

2、pthread_cond_timedwait()在本次循环中计时等待,线程进入休眠

3、等待超时,直接返回 false;

4、如果等待没有超时,期间锁被释放,线程会被唤醒,再次尝试获取锁 pthread_mutex_trylock(),如果获取成功返回true

5、即没有超时,被唤醒后也没有成功获取到锁(被其他线程抢先获得锁),重新计算超时时间进入下一次while循环

NSLock 坑(网上看的例子,解读一下)

代码先执行第 38 行,然后执行第 31 行,此时锁被 lock,然后继续执行 if 里面,因为里面有 testMethod(value-1),所以又开始调用[lock lock]方法,此时的锁一直处于 lock 状态,if 还没执行完,没有 unlock,所以NSlog 只会打印一次

你可能感兴趣的:(NSLock 解读)