Objective-C 关于锁的种类
2015-06-15 15:57
573 查看
Objective-C中不同方式实现锁(一)
转载http://www.tanhao.me/pieces/616.html/为什么需要使用锁,当然熟悉多线程的你,自然不会对它觉得陌生。
那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢?
今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这之前我们先构建一个测试用的类,假想它是我们的一个共享资源,method1与method2是互斥的,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @implementation TestObj - (void)method1 { NSLog(@"%@",NSStringFromSelector(_cmd)); } - (void)method2 { NSLog(@"%@",NSStringFromSelector(_cmd)); } @end |
1 2 3 4 5 6 7 8 9 10 11 12 1314 | //主线程中 TestObj *obj = [[TestObj alloc] init]; NSLock *lock = [[NSLock alloc] init]; //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [lock lock]; [obj method1]; sleep(10); [lock unlock]; }); //线程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1);//以保证让线程2的代码后执行 [lock lock]; [obj method2]; [lock unlock]; }); |
NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。
2.使用synchronized关键字构建的锁
当然在Objective-C中你还可以用@synchronized指令快速的实现锁:
1 2 3 4 5 6 7 8 9 10 11 12 1314 | //主线程中 TestObj *obj = [[TestObj alloc] init]; //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(obj){ [obj method1]; sleep(10); } }); //线程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); @synchronized(obj){ [obj method2]; } }); |
3.使用C语言的pthread_mutex_t实现的锁
1 2 3 4 5 6 7 8 9 10 11 12 1314 | //主线程中 TestObj *obj = [[TestObj alloc] init]; __block pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ pthread_mutex_lock(&mutex); [obj method1]; sleep(5); pthread_mutex_unlock(&mutex); }); //线程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); pthread_mutex_lock(&mutex); [obj method2]; pthread_mutex_unlock(&mutex); }); |
4.使用GCD来实现的”锁”
以上代码构建多线程我们就已经用到了GCD的dispatch_async方法,其实在GCD中也已经提供了一种信号机制,使用它我们也可以来构建一把”锁”(从本质意义上讲,信号量与锁是有区别,具体差异参加信号量与互斥锁之间的区别):
1 2 3 4 5 6 7 8 9 10 11 12 1314 | //主线程中 TestObj *obj = [[TestObj alloc] init]; dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [obj method1]; sleep(10); dispatch_semaphore_signal(semaphore); }); //线程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [obj method2]; dispatch_semaphore_signal(semaphore); }); |
好了,以上就是我所列举了几种方式来实现锁,当然锁大多数情况下也是配合多线程一起使用的,关于多线程编程,我这儿就不赘述了。
Objective-C中不同方式实现锁(二)
在上一文中,我们已经讨论过用Objective-C锁几种实现(跳转地址),也用代码实际的演示了如何通过构建一个互斥锁来实现多线程的资源共享及线程安全,今天我们继续讨论锁的一些高级用法。1.NSRecursiveLock递归锁
平时我们在代码中使用锁的时候,最容易犯的一个错误就是造成死锁,而容易造成死锁的一种情形就是在递归或循环中,如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 1314 | //主线程中 NSLock *theLock = [[NSLock alloc] init]; TestObj *obj = [[TestObj alloc] init]; //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ static void(^TestMethod)(int); TestMethod = ^(int value) { [theLock lock]; if (value > 0) { [obj method1]; sleep(5); TestMethod(value-1); } [theLock unlock]; }; TestMethod(5); }); //线程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(1); [theLock lock]; [obj method2]; [theLock unlock]; }); |
2.NSConditionLock条件锁
当我们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁:
1 2 3 4 5 6 7 8 9 10 11 12 1314 | //主线程中 NSConditionLock *theLock = [[NSConditionLock alloc] init]; //线程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i=0;i<=2;i++) { [theLock lock]; NSLog(@"thread1:%d",i); sleep(2); [theLock unlockWithCondition:i]; } }); //线程2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [theLock lockWhenCondition:2]; NSLog(@"thread2"); [theLock unlock]; }); |
//初始化一个NSConditionLock对象
- (id)initWithCondition:(NSInteger)condition
//返回一个Condition
- (NSInteger)condition
//获取和释放锁
1、– (BOOL)lockBeforeDate:(NSDate *)limit
//在指定时间前尝试获取锁,若成功则返回YES 否则返回NO
2、– (void)lockWhenCondition:(NSInteger)condition
//尝试获取锁。在加锁成功前接收对象的Condition必须与参数Condition 相同
3、– (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit
//同上,只是又加上了一个时间
4、– (BOOL)tryLock //尝试着获取锁
5、– (BOOL)tryLockWhenCondition:(NSInteger)condition
//如果接收对象的condition与给定的condition相等,则尝试获取锁.和lockWhenCondition区别是tryLockWhenCondition直接返回当前状态,没有阻塞线程。
6、– (void)unlockWithCondition:(NSInteger)condition
//解锁并设置接收对象的condition
3.NSDistributedLock分布式锁
以上所有的锁都是在解决多线程之间的冲突,但如果遇上多个进程或多个程序之间需要构建互斥的情景该怎么办呢?这个时候我们就需要使用到NSDistributedLock了,从它的类名就知道这是一个分布式的Lock,NSDistributedLock的实现是通过文件系统的,所以使用它才可以有效的实现不同进程之间的互斥,但NSDistributedLock并非继承于NSLock,它没有lock方法,它只实现了tryLock,unlock,breakLock,所以如果需要lock的话,你就必须自己实现一个tryLock的轮询,下面通过代码简单的演示一下吧:
程序A:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
1 2 3 4 5 6 7 | lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"]; [lock breakLock]; [lock tryLock]; sleep(10); [lock unlock]; NSLog(@"appA: OK"); }); |
1 2 3 4 5 6 78 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"]; while (![lock tryLock]) { NSLog(@"appB: waiting"); sleep(1); } [lock unlock]; NSLog(@"appB: OK"); }); |
NSCondition的用法
使用NSCondition,实现多线程的同步,即,可实现生产者消费者问题。基本思路是,首先要创建公用的NSCondition实例。然后:
消费者取得锁,取产品,如果没有,则wait,这时会释放锁,直到有线程唤醒它去消费产品;
生产者制造产品,首先也是要取得锁,然后生产,再发signal,这样可唤醒wait的消费者。
相关文章推荐
- swift 和 Objective-C 互相调用
- Programming with Objective-C 学习笔记
- iPhone/iOS中保存自定义对象(Custom Object/Custom Class)的数组(NSMutableArray/NSArray)到NSUserDefaults
- object-C与JAVA和C++对比
- Objective-C Method Swizzling 的最佳实践
- JSONObject与JSONArray的使用
- objective c 类目 延展 协议
- Objective-C类成员变量深度剖析
- Objective-C Method Swizzling 的最佳实践
- 学习笔记(objective-c)-类别(category)
- 学习笔记(objective-c)-重写isEqual方法
- objective-c 键值监听
- iOS开发--Objective-C之KVC
- Objective-C 知识点总结
- Objective-C面试题2
- Objective-C面试题
- [Objective-C] 006_Protocol(协议)
- Object-c-数组的使用
- 关于等待多长时间会引发ORA-04021: timeout occurred while waiting to lock object错误的猜测
- objective-c中线程编程一例