iOS线程同步和锁
来源:互联网 发布:2g和4g网络的区别 编辑:程序博客网 时间:2024/05/02 04:27
应用程序里面多个线程的存在引发了多个执行线程安全访问资源的潜在问题。两个线程同时修改同一资源有可能以意想不到的方式互相干扰。
iOS 提供了你可以使用的多个同步工具,从提供互斥访问你程序的有序的事件的工具等。以下个部分介绍了这些工具和如何在代码中使用他们来影响安全的访问程序的资源。
我们通过同一个例子来说明这些锁,当两个线程同时操作一个可变数组时,一个线程添加数据,一个线程删除数据,类似一个生产消费者模式,就会存在线程安全问题;
使用POSIX互斥锁
__block pthread_mutex_t mutex; pthread_mutex_init(&mutex,NULL); __block NSMutableArray* products = [[NSMutableArray alloc]init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (YES) { pthread_mutex_lock(&mutex); [products addObject:@"product"]; pthread_mutex_unlock(&mutex); } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (YES) { pthread_mutex_lock(&mutex); if (products.count != 0) { [products removeObjectAtIndex:0]; } pthread_mutex_unlock(&mutex); } });
在 Cocoa 程序中 NSLock 中实现了一个简单的互斥锁。所有锁(包括NSLock)的接口实际上都是通过NSLocking协议定义的,它定义了lock和unlock方法。你使用这些方法来获取和释放该锁。
除了标准的锁行为,NSLock类还增加了tryLock和lockBeforeDate:方法。方法tryLock试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程。相反,它只是返回NO。而lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回NO)。
NSLock* lock = [[NSLock alloc]init]; __block NSMutableArray* products = [[NSMutableArray alloc]init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (YES) { [lock lock]; [products addObject:@"product"]; [lock unlock]; /*避免阻塞*/ /* if([lock tryLock]) { [products addObject:@"product"]; [lock unlock]; } */ } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (YES) { [lock lock]; if (products.count != 0) { [products removeObjectAtIndex:0]; } [lock unlock]; } });
使用@synchronized指令
@synchronized指令是在Objective-C代码中创建一个互斥锁非常方便的方法。@synchronized指令做和其他互斥锁一样的工作(它防止不同的线程在同一时间获取同一个锁)。然而在这种情况下,你不需要直接创建一个互斥锁或锁对象。相反,你只需要简单的使用Objective-C对象作为锁的令牌
__block NSMutableArray* products = [[NSMutableArray alloc]init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(products) { while (YES) { [products addObject:@"product"]; } } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(products) { while (YES) { if (products.count != 0) { [products removeLastObject]; } } } });
使用单例的时候
@interface SingleObject : NSObject@property (strong, nonatomic) NSMutableArray *products;+ (instancetype)sharedInstance;- (void)addmethod;- (void)removemethod;@end@implementation SingleObject+ (instancetype)sharedInstance{ static SingleObject *sharedInstance_ = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ sharedInstance_ = [[[self class] alloc] init]; }); return sharedInstance_;}- (id)init{ self = [super init]; if (self) { self.products = [[NSMutableArray alloc]init]; } return self;}- (void)addmethod{ [self.products addObject:@"product"];}- (void)removemethod{ if (self.products.count != 0) { [self.products removeObjectAtIndex:0]; }}@end
SingleObject *object = [SingleObject sharedInstance]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(object) { while (YES) { [object addmethod]; } } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(object) { while (YES) { [object removemethod]; } } });
使用NSConditionLock对象
NSConditionLock对象定义了一个互斥锁,可以使用特定值来锁住和解锁。不要把该类型的锁和条件(NSCondition)混淆了。它的行为和条件有点类似,但是它们的实现非常不同。
#define HAS_DATA 1#define NO_DATA 0 NSConditionLock* condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; NSMutableArray* products = [[NSMutableArray alloc]init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while(1) { [condLock lock]; [products addObject:@"product"]; [condLock unlockWithCondition:HAS_DATA]; } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while(1) { [condLock lockWhenCondition:HAS_DATA]; [products removeLastObject]; [condLock unlockWithCondition:(products.count == 0 ? NO_DATA : HAS_DATA)]; } });
问题:以上的消费者都是在线程中轮询来取数据,这样会消耗大量cpu资源,如果可以在有数据的时候自己被告知,没有数据的时候空闲等待就好了,这时我们可以使用条件来完成,有以下两种方式(使用POSIX条件或者使用NSCondition类)。
使用NSCondition类
NSCondition类提供了和POSIX条件相同的语义,但是它把锁和条件数据结构封装在一个单一对象里面。结果是一个你可以像互斥锁那样使用的对象,然后等待特定条件。
消费者取得锁,取产品,如果没有,则wait,这时会释放锁,直到有线程唤醒它去消费产品
生产者制造产品,首先也是要取得锁,然后生产,再发signal,这样可唤醒wait的消费者
NSMutableArray* products = [[NSMutableArray alloc]init]; NSCondition* condition = [[NSCondition alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 消费者 while(1) { [condition lock]; while (products.count < 10) { [condition wait]; } [products removeObjectAtIndex:0]; [condition unlock]; } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 生产者 while(1) { [condition lock]; [products addObject:@"product"]; [condition signal]; [condition unlock]; } });
使用POSIX条件
pthread_mutex_t mutex;pthread_cond_t condition;Boolean ready_to_go = true; void MyCondInitFunction(){ pthread_mutex_init(&mutex); pthread_cond_init(&condition, NULL);} void MyWaitOnConditionFunction(){ // Lock the mutex. pthread_mutex_lock(&mutex); // If the predicate is already set, then the while loop is bypassed; // otherwise, the thread sleeps until the predicate is set. while(ready_to_go == false) { pthread_cond_wait(&condition, &mutex); } // Do work. (The mutex should stay locked.) // Reset the predicate and release the mutex. ready_to_go = false; pthread_mutex_unlock(&mutex);}
void SignalThreadUsingCondition(){ // At this point, there should be work for the other thread to do. pthread_mutex_lock(&mutex); ready_to_go = true; // Signal the other thread to begin work. pthread_cond_signal(&condition); pthread_mutex_unlock(&mutex);}
-参考《多线程编程指南》
- iOS线程同步和锁
- iOS 线程同步与锁
- iOS线程的同步和异步
- ios的线程和同步异步操作
- ios-同步异步、进程和线程
- java线程同步和锁
- 线程1 锁和同步
- Java 线程同步 和线程锁
- 线程和线程同步
- 线程和线程同步
- 线程和线程同步
- iOS多线程安全锁介绍---线程同步
- iOS 07-线程安全 同步锁
- ios 线程同步
- ios 线程同步
- ios互斥锁,线程同步
- 进程同步和线程同步
- threadlocal同步和线程同步
- zabbix 忘记密码,自定义key
- DFS
- 关于如何推动农村经济发展问题
- CrawlSpider问题总结
- Springmvc直接输出对象与接收对象问题
- iOS线程同步和锁
- Http post方式传递参数的格式
- 算法篇-数学基础-Cantor的数表
- 求阶乘N!末尾0的个数
- SpringMVC介绍之视图解析器ViewResolver
- 回溯法解决问题的3个步骤
- drawRect: 和 - (void)setNeedsDisplay 的一些理解
- 五台山地区草地生态系统服务价值估算
- Android基础:代码中实现界面动态布局