Objective-C中的同步线程的锁
2016-05-09 16:01
435 查看
概述
在多线程编程中往往会遇到多个线程同时访问共享的资源,这种情况我们需要通过同步线程来避免。也就是给线程加锁。因为
Objective-C是
C语言的超集。,严格的来说是真超集。所以
C语言当中的
pthread互斥锁在
Objective-C中也可以使用,但是
Objective-C中定义了本身自己的锁对象和锁协议,所以本篇介绍
Objective-C中的锁。
NSLock
NSLocking协议
@protocol NSLocking - (void)lock; - (void)unlock; @end
后面介绍的几种锁类型
NSLock,
NSConditionLock,
NSRecursiveLock,都实现了该协议可以统一用
lock与
unlock进行加锁与解锁。
NSLock使用
NSLock *lock = [[NSLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [lock lock]; //获取锁 NSLog(@"lock success"); sleep(5); NSLog(@"sleep end"); [lock unlock]; //放弃之前获取的锁 }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ [lock lock]; //获取锁,如果获取不到阻塞当前线程直到获取到锁 NSLog(@"remove lock"); [lock unlock]; //放弃获取到的锁 });
输出结果
lock success sleep end remove lock
当
NSLock对象发送
lock消息时先检查能不能获取到这个锁,如果此时在其他线程中正在使用这个锁那么阻塞当前线程一直等待其他线程使用完这个锁
unlock放弃这个锁后,才可以在自己当前的线程重新获取到,线程恢复。如果一直获取不到这个锁那么线程将一直阻塞,所以
lock与
unlock这两个方法一定要成对出现。当然还有不阻塞调用锁的线程方法
tryLock与
lockBeforeDate:
tryLock
tryLock尝试获取锁,如果获取不到返回
NO,反之
YES,不会阻塞当前调用它的线程
NSLock *lock = [[NSLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [lock lock]; //获取锁 NSLog(@"lock success"); sleep(5); NSLog(@"sleep end"); [lock unlock]; //放弃之前获取的锁 }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ if ([lock tryLock]) //尝试获取锁,如果获取不到返回NO,不会阻塞该线程 { NSLog(@"remove lock"); [lock unlock]; } else{ NSLog(@"obtain failure"); } });
输出结果
lock success obtain failure sleep end
获取失败是因为当前锁正在其他线程中使用。如果当前锁没有使用那么会返回
YES。
lockBeforeDate
lockBeforeDate阻塞调用它的线程,如果给定时间内不能够获取锁那么放弃获取并恢复线程。
NSLock *lock = [[NSLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [lock lock]; //获取锁 NSLog(@"lock success"); sleep(5); NSLog(@"sleep end"); [lock unlock]; //放弃之前获取的锁 }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:3]; if ([lock lockBeforeDate:date]) //尝试在未来的3s内获取锁,并阻塞该线程,如果3s内获取不到恢复线程 { NSLog(@"remove lock"); [lock unlock]; } else{ NSLog(@"obtain failure"); } });
输出结果
lock success obtain failure sleep end
如果3s内获取不到则返回NO,否则返回
YES
@synchronized
synchronized对一个对象提供锁定和解锁机制。synchronized会阻塞调用它的线程dispatch_async(dispatch_get_global_queue(0, 0), ^{ @synchronized (self) { [self logging:@"lock success"]; sleep(5); [self logging:@"sleep end"]; } }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ @synchronized (self) //等到上面线程执行完后才回执行下面的代码,此时会阻塞当前线程 { [self logging:@"remove lock"]; } });
输出结果
lock success sleep end remove lock
上面对自身对象进行加锁直到上面第一个GCD全部执行结束才会执行下面加锁的代码。
注意
Objective-C类自身也是对象所以可以对这些类对象使用
synchronized,此时是对整个对象类型进行线程同步。例如:
@synchronized ([self class]) { }
NSConditionLock
NSConditionLock条件锁,获取锁时必须与之前设置解锁的条件一样时才可以获取到,否则当前线程一直阻塞,直到条件一致时线程才可以恢复。
最典型的例子就是生产者-消费者场景,当数据为空时生产者生产数据此时消费者不能够获取数据,生产者生产数据后,消费者处理数据,直到消费者处理所有数据后,数据又为空,此时生产者继续生产数据。示例代码如下:
enum {NO_DATA_IN_QUEUE = 0,HAS_DATA_IN_QUEUE}; NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:NO_DATA_IN_QUEUE]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ while (YES) { [conditionLock lockWhenCondition:NO_DATA_IN_QUEUE]; NSLog(@"insert data"); sleep(3); NSLog(@"intset success"); [conditionLock unlockWithCondition:HAS_DATA_IN_QUEUE]; } }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ while (YES) { [conditionLock lockWhenCondition:HAS_DATA_IN_QUEUE]; NSLog(@"delete data"); sleep(3); NSLog(@"delete success"); [conditionLock unlockWithCondition:NO_DATA_IN_QUEUE]; } });
输出结果:
insert data intset success delete data delete success insert data intset success delete data delete success ...
NSRecursiveLock
NSRecursiveLock递归锁,当我们对一个递归函数同步线程时会在同一个线程多次获取锁,导致线程死锁,
NSRecursiveLock可以在同一个线程多次获取锁不会死锁。
NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ static void (^recursive)(int count); recursive = ^(int count){ [recursiveLock lock]; if (count>0) { NSLog(@"success lock"); sleep(3); recursive(--count); } [recursiveLock unlock]; }; recursive(3); });
上面这种情况如果使用
NSLock在没有解锁时继续获取锁,就会造成死锁导致线程一致堵塞。
NSDistributedLock
NSDistributedLock是Mac多线程开发中的互斥锁解决方案,在此不多做介绍。
相关文章推荐
- Objective-C中的Block
- Objective-C学习笔记和IOS入门
- ct returned too many results 错误:Error: executeQueryForObject returned too many results
- java.lang.ClassNotFoundException: net.sf.json.JSONObject
- Qt元对象系统(二)【根据moc文件解析Q_OBJECT】
- localStorage 保存对象Object
- iOS App开发中Objective-C使用正则表达式进行匹配的方法
- 《java入门第一季》之类(Object类)
- 《java入门第一季》之类(Object类)
- OBJ-C NSArray + NSDictionary学习笔记
- Java变参、C/C++/Objective_C变参
- 使HTML5 localStorage及sessionStorage支持储存Array OR Object
- 使HTML5 localStorage及sessionStorage支持储存Array OR Object
- 关于EnumerateObjectsUsingBlock和for-in之间的较量
- C# 编程遇到An object reference is required for the non-static field, method, or property错误
- 从头认识多线程-2.14 解决由同步的synchronized (newobject()) 引起的脏读的方法
- Object-c------NSDate的简单介绍
- Object-c------NSNumber和NSValue的简单介绍
- 上古时代 Objective-C 中哈希表的实现
- 函数对象状态(Function Object State)获取 -- 引用传递和for_each()