在iOS中有几种方法来解决多线程访问同一个内存地址的互斥同步问题:
一、@synchronized(id anObject),(最简单的方法)
会自动对参数对象加锁,保证临界区内的代码线程安全
@synchronized(self)
{
// 这段代码对其他 @synchronized(self) 都是互斥的
// self 指向同一个对象
}
二、NSLock
NSLock对象实现了NSLocking protocol,包含几个方法:
- lock,加锁
- unlock,解锁
- tryLock,尝试加锁,如果失败了,并不会阻塞线程,只是立即返回NO
- lockBeforeDate:,在指定的date之前暂时阻塞线程(如果没有获取锁的话),如果到期还没有获取锁,则线程被唤醒,函数立即返回NO
比如:
NSLock *theLock = [[NSLock alloc] init];
if ([theLock lock])
{
//do something here
[theLock unlock];
}
三、NSRecursiveLock,递归锁
NSRecursiveLock,多次调用不会阻塞已获取该锁的线程。
NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
void MyRecursiveFunction(int value)
{
[theLock lock];
if (value != 0) {
--value
MyRecursiveFunction(value);
}
[theLock unlock];
}
MyRecursiveFunction(5);
四、NSConditionLock,条件锁
NSConditionLock,条件锁,可以设置条件
//公共部分
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:
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:
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开始执行。
#import "MYDispatchSemaphoreViewController.h"
@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
网友评论