1.互斥锁
iOS中互斥锁的方式有@synchronized和NSLock,@synchronized块中的代码会加锁保护临界区,使得同时只有一个线程执行其中的代码,当前线程执行完毕之后,其它线程才可以进入执行代码块。NSLock的lock方法和unlock方法之间的部分会加锁保护。
@synchronized(string) {
//do something
}
NSLock *lock = [[NSLock alloc] init];
[lock lock];
//do something
[lock unlock];
递归锁又成为可重入锁,它是指一个线程可以重复地获取某个锁。递归锁可以使用引用计数的方式实现,获取一次锁,相应的引用计数加1,释放一次锁,相应的引用计数减1。
@interface ViewController ()
@property (nonatomic, strong)NSRecursiveLock *recursiveLock;
@end
@implementation ViewController
- (void)countFunction:(NSInteger)count
{
[self.recursiveLock lock];
if (count != 0) {
count--;
NSLog(@"count is %ld", (long)count);
[self countFunction:count];
}
[self.recursiveLock unlock];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.recursiveLock = [[NSRecursiveLock alloc] init];
[self countFunction:5];
}
方法countFunction递归调用了自身,如果这个地方使用NSLock将会造成死锁。
3.条件锁
条件锁可以设置条件,满足条件时获取或者释放锁。
@interface ViewController ()
@property (nonatomic, strong)NSConditionLock *conditionLock;
@property (nonatomic, assign)NSInteger count;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.count = 0;
self.conditionLock = [[NSConditionLock alloc] initWithCondition:0];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(countSend) object:nil];
[thread start];
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(countRecieve) object:nil];
[thread1 start];
}
- (void)countSend
{
while (true) {
[self.conditionLock lockWhenCondition:0];
self.count++;
NSLog(@"countSend,the count is %ld", (long)self.count);
sleep(1);
[self.conditionLock unlockWithCondition:1];
if (self.count > 5) {
break;
}
}
}
- (void)countRecieve
{
while(true) {
[self.conditionLock lockWhenCondition:1];
NSLog(@"countRecive,the count is %ld", (long)self.count);
sleep(1);
[self.conditionLock unlockWithCondition:0];
if (self.count > 5) {
break;
}
}
}
@end
上面的代码中,一个线程执行countSend方法改变计数,在改变计数之前先使用条件锁获取资源,改变计数之后改变条件锁的条件,释放资源,它类似于生产者的角色。另外一个线程执行countRecieve方法获取计数,在获取计数之前先视图获取条件锁,获取计数之后,改变条件锁的条件,释放资源,它类似于消费者的角色。
4.读写锁
在读者写者问题中,写操作是独占的,只能有一个线程同时进行写操作,读操作是共享的,可以有多个线程同时进行读操作。读写锁正是可以实现这种方式的要求,读写锁允许多个线程并发的读取,因而具有更高的并发性,它适用于读操作多于写操作的情况。GCD可以用于实现读写锁。
@interface ReadwriteString : NSObject
@property (nonatomic, strong)NSString *string;
@property (nonatomic, strong)dispatch_queue_t queue;
@end
@implementation ReadwriteString
- (instancetype)init
{
if (self = [super init]) {
_queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (void)modifyString:(NSString *)string
{
dispatch_barrier_async(self.queue, ^{
_string = string;
});
}
- (NSString *)acquireString
{
__block NSString *string = nil;
dispatch_sync(self.queue, ^{
string = self.string;
});
return string;
}
@end
代码中init方法创建了并行队列,modifyString方法在并行队列中使用了
dispatch_barrier_async,这个接口保证之前的任务完成之后在执行dispatch_barrier_async对应的block,之后的任务在dispatch_barrier_async对应的block完成后才执行。如果对string进行写操作,此时无法同时进行读操作,而读操作可以由多个任务并发执行的,这样就实现了一个读写锁。
5.自旋锁
相比于互斥所,自旋锁不会使得其它线程进入睡眠,在一个线程获取自旋锁以后,其它线程会不停地执行while循环知道获取资源。自旋锁省去了睡眠系统调用因而它有着较高的执行效率,自旋锁的缺点是如果一个线程迟迟不释放锁,其它线程因为不停执行循环而消耗CPU。自旋锁适合于临界区资源处理速度很快的场合。
#import "ViewController.h"
#import
@interface ViewController ()
{
OSSpinLock _lock;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
OSSpinLockLock(&_lock);
//do something
OSSpinLockUnlock(&_lock);
}