iOS 多线程的简单理解(4) 线程锁的简单使用

时间:2021-09-14 02:17:11

要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全

推荐一个原文链接 是关于 线程锁的基本使用的  http://blog.csdn.net/qq_30513483/article/details/52349968
这篇博客,也主要引用 这个链接的内容

4.1   OSSpinLock 自旋锁 :

线程通过busy-wait-loop的方式来获取锁,任时刻只有一个线程能够获得锁,其他线程忙等待直到获得锁。

spinlock在多处理器多线程环境的场景中有很广泛的使用,一般要求使用spinlock的临界区尽量简短,这样获取的锁可以尽快释放,以满足其他忙等的线程。

Spinlock和mutex不同,spinlock不会导致线程的状态切换(用户态->内核态),但是spinlock使用不当(如临界区执行时间过长)会导致cpu busy飙高。

/*

OS_SPINLOCK_INIT: 默认值为 0,在 locked 状态时就会大于 0unlocked状态下为 0
OSSpinLockLock(&oslock):上锁,参数为 OSSpinLock 地址
OSSpinLockUnlock(&oslock):解锁,参数为 OSSpinLock 地址
OSSpinLockTry(&oslock):尝试加锁,可以加锁则立即加锁并返回
YES
,反之返回 NO

这里顺便提一下trylocklock使用场景:

当前线程锁失败,也可以继续其它任务,用 trylock 合适
当前线程只有锁成功后,才会做一些有意义的工作,那就 lock,没必要轮询 trylock

*/

使用:::导入 #import <libkern/OSAtomic.h>  iOS  10.0 后被取消 ,需要更换这个锁

- (void)osspinLock{
    __block OSSpinLock oslock = OS_SPINLOCK_INIT;
    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"线程1 准备上锁  %@",[NSThread currentThread]);
        OSSpinLockLock(&oslock);
        sleep(4);
        NSLog(@"线程1 代码执行  %@",[NSThread currentThread]);
        OSSpinLockUnlock(&oslock);
        NSLog(@"线程1 解锁成功  %@",[NSThread currentThread]);
        NSLog(@"--------------------------------------------------------");
    });
    
    //线程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"线程2 准备上锁  %@",[NSThread currentThread]);
        OSSpinLockLock(&oslock);
        NSLog(@"线程2 代码执行  %@",[NSThread currentThread]);
        OSSpinLockUnlock(&oslock);
        NSLog(@"线程2 解锁成功  %@",[NSThread currentThread]);
    });
}

执行结果:::

2017-12-21 15:24:11.495148+0800 DeadThread[12619:4480008] 线程1 准备上锁  <NSThread: 0x608000071940>{number = 3, name = (null)}
2017-12-21 15:24:11.495148+0800 DeadThread[12619:4480007] 线程2 准备上锁  <NSThread: 0x60c000261180>{number = 4, name = (null)}
2017-12-21 15:24:11.495376+0800 DeadThread[12619:4480007] 线程2 代码执行  <NSThread: 0x60c000261180>{number = 4, name = (null)}
2017-12-21 15:24:11.495470+0800 DeadThread[12619:4480007] 线程2 解锁成功  <NSThread: 0x60c000261180>{number = 4, name = (null)}
2017-12-21 15:24:15.498949+0800 DeadThread[12619:4480008] 线程1 代码执行  <NSThread: 0x608000071940>{number = 3, name = (null)}
2017-12-21 15:24:15.499124+0800 DeadThread[12619:4480008] 线程1 解锁成功  <NSThread: 0x608000071940>{number = 3, name = (null)}
2017-12-21 15:24:15.499216+0800 DeadThread[12619:4480008] --------------------------------------------------------

总结结果:::

1.两个任务都要 异步 + 并发:所以会重新开启两个子线程;

2.两个线程都有锁:当锁定后,会执行完这个任务,才会执行下一个任务;

3.这个结果 只是一中情况,异步并发 会先发起哪个任务是不定的;

对上面的代码稍作修改:::: 给 解锁的代码  添加注释

- (void)osspinLock{

    __block OSSpinLock oslock = OS_SPINLOCK_INIT;
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 准备上锁 %@",[NSThread currentThread]);
OSSpinLockLock(&oslock);
sleep(4);
NSLog(@"线程1 代码执行 %@",[NSThread currentThread]);
// OSSpinLockUnlock(&oslock);
NSLog(@"线程1 解锁成功 %@",[NSThread currentThread]);
NSLog(@"--------------------------------------------------------");
}); //线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 准备上锁 %@",[NSThread currentThread]);
OSSpinLockLock(&oslock);
NSLog(@"线程2 代码执行 %@",[NSThread currentThread]);
// OSSpinLockUnlock(&oslock);
NSLog(@"线程2 解锁成功 %@",[NSThread currentThread]);
}); }

执行结果::::

2017-12-21 15:29:34.099561+0800 DeadThread[12653:4494849] 线程1 准备上锁  <NSThread: 0x60c000262100>{number = 3, name = (null)}
2017-12-21 15:29:34.099561+0800 DeadThread[12653:4494848] 线程2 准备上锁 <NSThread: 0x60000047bf00>{number = 4, name = (null)}
2017-12-21 15:29:38.100529+0800 DeadThread[12653:4494849] 线程1 代码执行 <NSThread: 0x60c000262100>{number = 3, name = (null)}
2017-12-21 15:29:38.100739+0800 DeadThread[12653:4494849] 线程1 解锁成功 <NSThread: 0x60c000262100>{number = 3, name = (null)}
2017-12-21 15:29:38.100880+0800 DeadThread[12653:4494849] --------------------------------------------------------

总结结果:::

1.两个任务,每个都含有锁:当有个任务先得到执行的时候,任务执行完没有了解锁的过程

但是另一个任务,会一直等待 锁解除才能执行, 始终不会执行……

4.2  pthread_mutex  互斥锁 ::

使用::#import <pthread.h>
/**
 pthread_mutex 中也有个pthread_mutex_trylock(&pLock),
 和上面提到的 OSSpinLockTry(&oslock)
 区别在于,前者可以加锁时返回的是 0,否则返回一个错误提示码;
 后者返回的 YES和NO
 */

-(void)mutexLock{

    static pthread_mutex_t pLock;
pthread_mutex_init(&pLock, NULL);
//1.线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 准备上锁 %@",[NSThread currentThread]);
pthread_mutex_lock(&pLock);
sleep(3);
NSLog(@"线程1 执行 %@",[NSThread currentThread]);
pthread_mutex_unlock(&pLock);
NSLog(@"线程1 成功解锁 %@",[NSThread currentThread]); }); //1.线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 准备上锁 %@",[NSThread currentThread]);
pthread_mutex_lock(&pLock);
sleep(3);
NSLog(@"线程2 执行 %@",[NSThread currentThread]);
pthread_mutex_unlock(&pLock);
NSLog(@"线程2 成功解锁 %@",[NSThread currentThread]);
}); }

执行结果:::

2017-12-21 15:37:37.219816+0800 DeadThread[12685:4529083] 线程2 准备上锁  <NSThread: 0x60000006c980>{number = 4, name = (null)}
2017-12-21 15:37:37.219816+0800 DeadThread[12685:4529086] 线程1 准备上锁 <NSThread: 0x604000469880>{number = 3, name = (null)}
2017-12-21 15:37:40.223145+0800 DeadThread[12685:4529083] 线程2 执行 <NSThread: 0x60000006c980>{number = 4, name = (null)}
2017-12-21 15:37:40.223404+0800 DeadThread[12685:4529083] 线程2 成功解锁 <NSThread: 0x60000006c980>{number = 4, name = (null)}
2017-12-21 15:37:43.226685+0800 DeadThread[12685:4529086] 线程1 执行 <NSThread: 0x604000469880>{number = 3, name = (null)}
2017-12-21 15:37:43.226809+0800 DeadThread[12685:4529086] 线程1 成功解锁 <NSThread: 0x604000469880>{number = 3, name = (null)}

结果分析:::

1.异步 + 并发 -> 两个线程;

2.先加锁的任务 先完成,等待任务完成解锁,在完成下一个任务;

4.3   pthread_mutex(recursive) 递归锁

/**
 经过上面几种例子,我们可以发现:
 加锁后只能有一个线程访问该对象,后面的线程需要排队,
 并且 lock 和 unlock 是对应出现的,同一线程多次 lock 是不允许的,

而递归锁允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作。
 
 上面的代码如果我们用 pthread_mutex_init(&pLock, NULL) 初始化会出现死锁的情况,递归锁能很好的避免这种情况的死锁;
 */

-(void)recursiveLock{

    static pthread_mutex_t pLock;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); //初始化attr并且给它赋予默认
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //设置锁类型,这边是设置为递归锁
pthread_mutex_init(&pLock, &attr);
pthread_mutexattr_destroy(&attr); //销毁一个属性对象,在重新进行初始化之前该结构不能重新使用 static void (^RecursiveBlock)(int); //1.线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ RecursiveBlock = ^(int value) {
pthread_mutex_lock(&pLock);
if (value > 0) {
NSLog(@"value: %d", value);
RecursiveBlock(value - 1);
}
pthread_mutex_unlock(&pLock);
};
RecursiveBlock(5); }); }

执行结果:::

2017-12-21 15:45:39.095417+0800 DeadThread[12721:4562499] value: 5
2017-12-21 15:45:39.095583+0800 DeadThread[12721:4562499] value: 4
2017-12-21 15:45:39.096599+0800 DeadThread[12721:4562499] value: 3
2017-12-21 15:45:39.097190+0800 DeadThread[12721:4562499] value: 2
2017-12-21 15:45:39.097645+0800 DeadThread[12721:4562499] value: 1

结果分析:::

1.开启新的线程;

2.递归锁 ->允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作;

4.4  dispatch_semaphore 信号量

/**

dispatch_semaphore_create(1): 传入值必须 >=0, 若传入为 0 则阻塞线程并等待timeout,时间到后会执行其后的语句
dispatch_semaphore_wait(signal, overTime):可以理解为 lock,会使得
signal-1
dispatch_semaphore_signal(signal):可以理解为 unlock,会使得
signal
+1

*/

-(void)GCDSemaphore{

    dispatch_semaphore_t signal = dispatch_semaphore_create(1); //传入值必须 >=0, 若传入为0则阻塞线程并等待timeout,时间到后会执行其后的语句
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC); //线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 等待ing %@",[NSThread currentThread]);
dispatch_semaphore_wait(signal, overTime); //signal 值 -1
sleep(4); NSLog(@"线程1 执行 %@",[NSThread currentThread]);
dispatch_semaphore_signal(signal); //signal 值 +1
NSLog(@"线程1 发送信号 %@",[NSThread currentThread]);
NSLog(@"--------------------------------------------------------");
}); //线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 等待ing %@",[NSThread currentThread]);
dispatch_semaphore_wait(signal, overTime);
sleep(4); NSLog(@"线程2 执行 %@",[NSThread currentThread]);
dispatch_semaphore_signal(signal);
NSLog(@"线程2 发送信号 %@",[NSThread currentThread]);
});
}

执行结果:::

2017-12-21 15:49:55.355078+0800 DeadThread[12761:4592703] 线程1 等待ing  <NSThread: 0x60c000076400>{number = 3, name = (null)}
2017-12-21 15:49:55.355079+0800 DeadThread[12761:4592705] 线程2 等待ing <NSThread: 0x60c00007d740>{number = 5, name = (null)}
2017-12-21 15:49:59.360317+0800 DeadThread[12761:4592703] 线程1 执行 <NSThread: 0x60c000076400>{number = 3, name = (null)}
2017-12-21 15:49:59.360482+0800 DeadThread[12761:4592703] 线程1 发送信号 <NSThread: 0x60c000076400>{number = 3, name = (null)}
2017-12-21 15:49:59.360568+0800 DeadThread[12761:4592703] --------------------------------------------------------
2017-12-21 15:50:02.358932+0800 DeadThread[12761:4592705] 线程2 执行 <NSThread: 0x60c00007d740>{number = 5, name = (null)}
2017-12-21 15:50:02.359109+0800 DeadThread[12761:4592705] 线程2 发送信号 <NSThread: 0x60c00007d740>{number = 5, name = (null)}

结果分析:::
1.初始信号量大于0

可以发现,因为我们初始化信号量的时候是大于 0 的,所以并没有阻塞线程,而是直接执行了 线程1 线程2。

把信号量设置为 0 修改上面代码

dispatch_semaphore_t signal = dispatch_semaphore_create(0);

执行结果::::

2017-12-21 15:53:43.545606+0800 DeadThread[12804:4615777] 线程2 等待ing  <NSThread: 0x604000076880>{number = 4, name = (null)}
2017-12-21 15:53:43.545651+0800 DeadThread[12804:4615776] 线程1 等待ing <NSThread: 0x60000026cbc0>{number = 5, name = (null)}
2017-12-21 15:53:50.553973+0800 DeadThread[12804:4615777] 线程2 执行 <NSThread: 0x604000076880>{number = 4, name = (null)}
2017-12-21 15:53:50.553973+0800 DeadThread[12804:4615776] 线程1 执行 <NSThread: 0x60000026cbc0>{number = 5, name = (null)}
2017-12-21 15:53:50.554140+0800 DeadThread[12804:4615777] 线程2 发送信号 <NSThread: 0x604000076880>{number = 4, name = (null)}
2017-12-21 15:53:50.554144+0800 DeadThread[12804:4615776] 线程1 发送信号 <NSThread: 0x60000026cbc0>{number = 5, name = (null)}
2017-12-21 15:53:50.554252+0800 DeadThread[12804:4615776] --------------------------------------------------------

结果分析:::

1. 初始信号量为0 ;可以看到这时候我们设置的 overTime 生效了。
可以记住这个例子::::
关于信号量,我们可以用停车来比喻:

    停车场剩余4个车位,那么即使同时来了四辆车也能停的下。如果此时来了五辆车,那么就有一辆需要等待。
信号量的值(signal)就相当于剩余车位的数目,dispatch_semaphore_wait 函数就相当于来了一辆车,dispatch_semaphore_signal 就相当于走了一辆车。
停车位的剩余数目在初始化的时候就已经指明了(dispatch_semaphore_create(long value)),调用一次 dispatch_semaphore_signal,剩余的车位就增加一个;
调用一次dispatch_semaphore_wait 剩余车位就减少一个;当剩余车位为 0 时,再来车(即调用 dispatch_semaphore_wait)就只能等待。
有可能同时有几辆车等待一个停车位。有些车主没有耐心,给自己设定了一段等待时间,这段时间内等不到停车位就走了,如果等到了就开进去停车。
而有些车主就像把车停在这,所以就一直等下去。

4.5  nslock 普通锁

/**
 lock、unlock:不多做解释,和上面一样
 trylock:能加锁返回 YES 并执行加锁操作,相当于 lock,反之返回 NO
 lockBeforeDate:这个方法表示会在传入的时间内尝试加锁,若能加锁则执行加锁操作并返回 YES,反之返回 NO
 */

- (void)nslock{

    NSLock *lock = [NSLock new];
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程1 尝试加速ing...");
[lock lock];
sleep(5);// 可以设置 3 和下面的等待 4 进行比交
NSLog(@"线程1 执行");
[lock unlock];
NSLog(@"线程1 解锁成功");
}); //线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"线程2 尝试加速ing..."); BOOL x = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:4]];
if (x) {
NSLog(@"线程2 执行");
[lock unlock];
}else{
NSLog(@"失败");
} // [lock lock];
// NSLog(@"线程2 执行");
// [lock unlock];
// NSLog(@"线程2 解锁成功"); });

执行结果:::

2017-12-21 15:57:18.176823+0800 DeadThread[12833:4641424] 线程2 尝试加速ing...
2017-12-21 15:57:18.176823+0800 DeadThread[12833:4641448] 线程1 尝试加速ing...
2017-12-21 15:57:22.179919+0800 DeadThread[12833:4641424] 失败
2017-12-21 15:57:23.180686+0800 DeadThread[12833:4641448] 线程1 执行
2017-12-21 15:57:23.180876+0800 DeadThread[12833:4641448] 线程1 解锁成功

结果分析:::

1. 在4s 内,加锁是失败的;

4.6   NSRecursiveLock 递归锁

/**
 递归锁可以被同一线程多次请求,而不会引起死锁。这主要是用在循环或递归操作中。
 - (BOOL)tryLock;
 - (BOOL)lockBeforeDate:(NSDate *)limit;
 */

-(void)nsrecursiveLock{

    NSRecursiveLock *rLock = [NSRecursiveLock new];
// NSLock *rLock = [NSLock new]; 换用这个 造成死锁 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ static void (^RecursiveBlock)(int); RecursiveBlock = ^(int value) { [rLock lock]; if (value > 0) {
NSLog(@"线程%d", value);
RecursiveBlock(value - 1);
} [rLock unlock];
}; RecursiveBlock(4);
});
}

执行结果:::

2017-12-21 16:02:15.559443+0800 DeadThread[12860:4670051] 线程4
2017-12-21 16:02:15.559602+0800 DeadThread[12860:4670051] 线程3
2017-12-21 16:02:15.559712+0800 DeadThread[12860:4670051] 线程2
2017-12-21 16:02:15.559929+0800 DeadThread[12860:4670051] 线程1

结果分析:::

1.类似于 4.2的递归锁;

4.6  @synchronized 条件锁

-(void)synchronized{

    //线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized (self) {
NSLog(@"线程1加锁成功 %@",[NSThread currentThread]); sleep(2);
NSLog(@"线程1");
}
}); //线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized (self) {
NSLog(@"线程2加锁成功 %@",[NSThread currentThread]); NSLog(@"线程2");
}
}); }

执行结果:::

2017-12-21 16:04:22.076568+0800 DeadThread[12887:4680292] 线程1加锁成功  <NSThread: 0x60000006fa00>{number = 5, name = (null)}
2017-12-21 16:04:24.077240+0800 DeadThread[12887:4680292] 线程1
2017-12-21 16:04:24.077530+0800 DeadThread[12887:4680295] 线程2加锁成功 <NSThread: 0x60400027d840>{number = 4, name = (null)}
2017-12-21 16:04:24.077611+0800 DeadThread[12887:4680295] 线程2

结果分析:::

1.@synchronized(obj),保护这个对象,相当于 NSLock 锁定了 obj 一样;

4.7 //NSCondition  条件锁

/**
 wait:进入等待状态
 waitUntilDate::让一个线程等待一定的时间
 signal:唤醒一个等待的线程
 broadcast:唤醒所有等待的线程
 */

-(void)conditionLockOne{

    NSCondition *cLock = [NSCondition new];
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"start %@",[NSThread currentThread]); [cLock lock];
[cLock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; NSLog(@"线程1 执行 %@",[NSThread currentThread]); [cLock unlock]; NSLog(@"end %@",[NSThread currentThread]);
}); }

执行结果:::

2017-12-21 16:16:14.096649+0800 DeadThread[12936:4727712] start <NSThread: 0x60800026fb80>{number = 3, name = (null)}
2017-12-21 16:16:16.100037+0800 DeadThread[12936:4727712] 线程1 执行 <NSThread: 0x60800026fb80>{number = 3, name = (null)}
2017-12-21 16:16:16.100296+0800 DeadThread[12936:4727712] end <NSThread: 0x60800026fb80>{number = 3, name = (null)}

结果分析:::

1.condition  可以像 nslock 样使用

-(void)conditionLockTwo{

    NSCondition *cLock = [NSCondition new];

    //线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cLock lock]; NSLog(@"线程1加锁成功 %@",[NSThread currentThread]);
[cLock wait];
NSLog(@"线程1 %@",[NSThread currentThread]);
[cLock unlock];
NSLog(@"线程1 解锁 %@",[NSThread currentThread]);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cLock lock]; NSLog(@"线程2加锁成功 %@",[NSThread currentThread]);
[cLock wait];
NSLog(@"线程2 %@",[NSThread currentThread]);
[cLock unlock]; NSLog(@"线程2 解锁 %@",[NSThread currentThread]);
}); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(2);
NSLog(@"唤醒一个等待的线程 %@",[NSThread currentThread]);
[cLock signal];
// [cLock signal]; }); // dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// sleep(2);
// NSLog(@"唤醒所有等待的线程 %@",[NSThread currentThread]);
// [cLock broadcast];
// });
}

执行结果:::

2017-12-21 16:18:01.779627+0800 DeadThread[12957:4738568] 线程1加锁成功  <NSThread: 0x600000464d00>{number = 5, name = (null)}
2017-12-21 16:18:01.780054+0800 DeadThread[12957:4738569] 线程2加锁成功 <NSThread: 0x60800007b140>{number = 3, name = (null)}
2017-12-21 16:18:03.784645+0800 DeadThread[12957:4738565] 唤醒一个等待的线程 <NSThread: 0x60400007d980>{number = 6, name = (null)}
2017-12-21 16:18:03.784862+0800 DeadThread[12957:4738568] 线程1 <NSThread: 0x600000464d00>{number = 5, name = (null)}
2017-12-21 16:18:03.784948+0800 DeadThread[12957:4738568] 线程1 解锁 <NSThread: 0x600000464d00>{number = 5, name = (null)}

结果分析:::

1. 可以 设置wait 属性,然后执行唤醒命令,唤醒线程,或者唤醒 所有 wait的线程

/**
 tryLockWhenCondition:
 
 result
 
 我们在初始化 NSConditionLock 对象时,给了他的标示为 0
 执行 tryLockWhenCondition:时,我们传入的条件标示也是 0,所 以线程1 加锁成功
 执行 unlockWithCondition:时,这时候会把condition由 0 修改为 1
 因为condition 修改为了 1, 会先走到 线程3,然后 线程3 又将 condition 修改为 3
 最后 走了 线程2 的流程
 
 从上面的结果我们可以发现,NSConditionLock 还可以实现任务之间的依赖。

*/

-(void)conditionLockThree{

    NSConditionLock *cLock = [[NSConditionLock alloc] initWithCondition:0];

    //线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if([cLock tryLockWhenCondition:0]){
NSLog(@"线程1");
[cLock unlockWithCondition:1];
}else{
NSLog(@"失败");
}
}); //线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cLock lockWhenCondition:3];
NSLog(@"线程2");
[cLock unlockWithCondition:2];
}); //线程3
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cLock lockWhenCondition:1];
NSLog(@"线程3");
[cLock unlockWithCondition:3];
}); }

执行结果:::

2017-12-21 16:20:25.387192+0800 DeadThread[12984:4750303] 线程1
2017-12-21 16:20:25.387338+0800 DeadThread[12984:4750301] 线程3
2017-12-21 16:20:25.387430+0800 DeadThread[12984:4750304] 线程2