iOS 多线程的简单理解(4) 线程锁的简单使用
要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全
推荐一个原文链接 是关于 线程锁的基本使用的 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
状态时就会大于0
,unlocked
状态下为0
OSSpinLockLock(&oslock):上锁,参数为OSSpinLock
地址
OSSpinLockUnlock(&oslock):解锁,参数为OSSpinLock
地址
OSSpinLockTry(&oslock):尝试加锁,可以加锁则立即加锁并返回,反之返回
YESNO
这里顺便提一下trylock
和lock
使用场景:
当前线程锁失败,也可以继续其它任务,用 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] --------------------------------------------------------
结果分析:::
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
iOS 多线程的简单理解(4) 线程锁的简单使用的更多相关文章
- iOS多线程开发资源抢夺和线程间的通讯问题
说到多线程就不得不提多线程中的锁机制,多线程操作过程中往往多个线程是并发执行的,同一个资源可能被多个线程同时访问,造成资源抢夺,这个过程中如果没有锁机制往往会造成重大问题.举例来说,每年春节都是一票难 ...
- ios 多线程开发(二)线程管理
线程管理 iOS和OS X中每一个进程(或程序)由一个或多个线程组成.程序由一个运行main方法的线程开始,中间可以产生其他线程来执行一些指定的功能. 当程序产生一个新线程后,这个线程在程序进程空间内 ...
- Java线程锁一个简单Lock
/** * @author * * Lock 是java.util.concurrent.locks下提供的java线程锁,作用跟synchronized类似, * 单是比它更加面向对象,两个线程执行 ...
- Android多线程研究(9)——线程锁Lock
在前面我们在解决线程同步问题的时候使用了synchronized关键字,今天我们来看看Java 5.0以后提供的线程锁Lock. Lock接口的实现类提供了比使用synchronized关键字更加灵活 ...
- 多线程11_张孝祥 java5的线程锁技术
本例子因为两个线程公用同线程中,使用同一个对象,实现了他们公用一把锁,实现了同一个方法的互斥. package locks; /** *会被打乱的效果 */ public class LockTest ...
- 简单理解SQL Server锁机制
多个用户同时对数据库的并发操作时,可能会遇到下面几种情况,导致数据前后不一致: 1,A.B事务同时对同一个数据进行修改,后提交的人的修改结果会破坏先提交的(丢失更新): 2,事务A修改某一条数据还未提 ...
- 关于C#多线程、易失域、锁的分享
一.多线程 windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,CLR(公共语言运行库)为该进程创建了一 ...
- python线程锁
import time,threading balance = 0 lock = threading.Lock() def change_it(n): global balance balance = ...
- iOS边练边学--多线程介绍、NSThread的简单实用、线程安全以及线程之间的通信
一.iOS中的多线程 多线程的原理(之前多线程这块没好好学,之前对多线程的理解也是错误的,这里更正,好好学习这块) iOS中多线程的实现方案有以下几种 二.NSThread线程类的简单实用(直接上代码 ...
随机推荐
- learning java AWT 剪贴板 传递文本
import javax.swing.*; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.dat ...
- 结构化异常SEH处理机制详细介绍(一)
结构化异常处理(SEH)是Windows操作系统提供的强大异常处理功能.而Visual C++中的__try{}/__finally{}和__try{}/__except{}结构本质上是对Window ...
- C二维数组用指针地址遍历
#include <stdio.h> #include <stdlib.h> int main(){ int a = 100; void *p = &a; printf ...
- Sage Math中的语法
1.赋值后不能立即输出,而需要停顿.x= 3 不能输出显示,而 x= 3; x 可以显示. 2.可以用分号连续书写多行. 3.矩阵可以用 mtx[i, j]引用,但是行列号通常从0开始,维度n, m ...
- navicat 链接阿里云服务器数据库报80070007 的错误
navicat用ssh跳转登录mysql连接时报: 80070007: SSH Tunnel: Server does not support diffie-hellman-group1-sha1 f ...
- 绕流振动UDF【转载】
宏DEFINE_GRID_MOTION用来移动任意边界和流体区域内的网格节点.它提供了对节点和网格最大限度的操作,可以将刚体运动.变形和相对运动等结合起来.但是使用此UDF时,每一个时间步都必须执行. ...
- docker运行puppeteer出现defucnt僵尸进程
其实这是docker的一个bug,就是在运行前加--init即可,注意这个在mac中没有只在linux上有. docker run --init -d ..... 具体内容参见:https://sta ...
- ubuntu之路——day8.2 深度学习优化算法之指数加权平均与偏差修正,以及基于指数加权移动平均法的动量梯度下降法
首先感谢吴恩达老师的免费公开课,以下图片均来自于Andrew Ng的公开课 指数加权平均法 在统计学中被称为指数加权移动平均法,来看下面一个例子: 这是伦敦在一些天数中的气温分布图 Vt = βVt- ...
- 微信小程序实现左侧滑栏
前言 一直想给项目中的小程序设置侧滑栏,将退出按钮放到侧滑中,但是小程序没有提供相应的控件和API,因此只能自己手动实现,网上很多大神造的轮子很不错,本文就在是站在巨人的肩膀上实现. 效果 先看看效果 ...
- NoSql数据库Redis系列(4)——Redis数据持久化(AOF)
上一篇文章我们介绍了Redis的RDB持久化,RDB 持久化存在一个缺点是一定时间内做一次备份,如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失).对于数据完整性要求很严 ...