本文主要讨论OC中各种锁的使用。首先,创建一个用来测试的类。假设这个测试类是共享的资源,然后method1和method2是互斥的。
测试类:
#import "TestObject.h"
@implementation TestObject
- (void)method1
{
NSLog(@"%@",NSStringFromSelector(_cmd));
}
- (void)method2
{
NSLog(@"%@",NSStringFromSelector(_cmd));
}
@end
1.使用NSLock实现的锁
TestObject *obj = [[TestObject alloc] init];
NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
[obj method1];
sleep(10);
[lock unlock];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);//以保证让线程2的代码后执行
[lock lock];
[obj method2];
[lock unlock];
});
除lock和unlock方法外,NSLock还提供了tryLock
和lockBeforeDate
:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。
2.使用synchronized关键字构建的锁
TestObject *obj = [[TestObject alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(obj){
[obj method1];
sleep(10);
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
@synchronized(obj){
[obj method2];
}
});
@synchronized指令使用的obj为该锁的唯一标识,只有当标识相同时,才为满足互斥,如果线程2中的@synchronized(obj)
改为@synchronized(other)
,刚线程2就不会被阻塞,@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象
,便可以实现锁的机制,但作为一种预防措施,@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
3.使用C语言的pthread_mutex_t实现的锁
TestObject *obj = [[TestObject alloc] init];
__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
pthread_mutex_lock(&mutex);
[obj method1];
sleep(5);
pthread_mutex_unlock(&mutex);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
pthread_mutex_lock(&mutex);
[obj method2];
pthread_mutex_unlock(&mutex);
});
由于pthread_mutex_t定义在C语言中的pthread.h
,所以导入头文件要使用#include
。
4.使用GCD来实现的”锁”
以上代码构建多线程我们就已经用到了GCD的dispatch_async
方法,其实在GCD中也已经提供了一种信号机制
,使用它我们也可以来构建一把”锁”(从本质意义上讲,信号量
与锁
是有区别,具体差异请自行查阅信号量与互斥锁之间的区别)
TestObject *obj = [[TestObject alloc] init];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(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);
});
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);
});
以上就是常用的锁机制,在网上查资料都说OSSpinLock
自旋锁效率是最高的,但是目前很多人都说自旋锁已经不再安全。如果算上OSSpinLock,各种锁的效率如下
OSSpinLock > pthread_mutex > NSLock > semaphore > @Sych
如果有有关于OSSpinLock是否安全的问题会及时更新。
网友评论