在iOS中有几种方法来解决多线程访问同一个内存地址的互斥同步问题:
一、@synchronized(id anObject),(最简单的方法)
会自动对参数对象加锁,保证临界区内的代码线程安全
12345 @synchronized(self){// 这段代码对其他 @synchronized(self) 都是互斥的// self 指向同一个对象}
二、NSLock
NSLock对象实现了NSLocking protocol,包含几个方法:
- lock,加锁
- unlock,解锁
- tryLock,尝试加锁,如果失败了,并不会阻塞线程,只是立即返回NO
- lockBeforeDate:,在指定的date之前暂时阻塞线程(如果没有获取锁的话),如果到期还没有获取锁,则线程被唤醒,函数立即返回NO
比如:
123456 NSLock *theLock = [[NSLock alloc] init];if ([theLock lock]){//do something here[theLock unlock];}
三、NSRecursiveLock,递归锁
NSRecursiveLock,多次调用不会阻塞已获取该锁的线程。
1234567891011 NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];void MyRecursiveFunction(int value){[theLock lock];if (value != 0) {--valueMyRecursiveFunction(value);}[theLock unlock];}MyRecursiveFunction(5);
四、NSConditionLock,条件锁
NSConditionLock,条件锁,可以设置条件
123456789101112131415 //公共部分id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];//线程一,生产者while(true) {[condLock lockWhenCondition:NO_DATA];//生产数据[condLock unlockWithCondition:HAS_DATA];}//线程二,消费者while (true){[condLock lockWhenCondition:HAS_DATA];//消费[condLock unlockWithCondition:NO_DATA];}
五、NSDistributedLock,分布锁
NSDistributedLock,分布锁,文件方式实现,可以跨进程
- 用tryLock方法获取锁。
- 用unlock方法释放锁。
如果一个获取锁的进程在释放锁之前挂了,那么锁就一直得不到释放了,此时可以通过breakLock强行获取锁。
程序A:
12345678 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];[lock breakLock];[lock tryLock];sleep(10);[lock unlock];NSLog(@"appA: OK");});程序B:
123456789 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");});先运行程序A,然后立即运行程序B,根据打印你可以清楚的发现,当程序A刚运行的时候,程序B一直处于等待中,当大概10秒过后,程序B便打印出了appB:OK的输出,以上便实现了两上不同程序之间的互斥。/Users/mac/Desktop/earning__是一个文件或文件夹的地址,如果该文件或文件夹不存在,那么在tryLock返回YES时,会自动创建该文件/文件夹。在结束的时候该文件/文件夹会被清除,所以在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。
六、条件信号量dispatch_semaphore_t
dispatch_semaphore_t
:GCD中信号量,也可以解决资源抢占问题,支持信号通知和信号等待。每当发送一个信号通知,则信号量+1;每当发送一个等待信号时信号量-1,;如果信号量为0则信号会处于等待状态,直到信号量大于0开始执行。
12345678910111213141516171819202122232425262728293031323334 @interface MYDispatchSemaphoreViewController (){dispatch_semaphore_t semaphore;}@end@implementation MYDispatchSemaphoreViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view./*** 创建一个信号量为1的信号**/semaphore = dispatch_semaphore_create(1);}- (void)getIamgeName:(NSMutableArray *)imageNames{NSString *imageName;/*** semaphore:等待信号DISPATCH_TIME_FOREVER:等待时间wait之后信号量-1,为0*/dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);if (imageNames.count>0) {imageName = [imageNames lastObject];[imageNames removeObject:imageName];}/*** 发送一个信号通知,这时候信号量+1,为1*/dispatch_semaphore_signal(semaphore);}@end