iOS中的锁

1.互斥锁

iOS中互斥锁的方式有@synchronized和NSLock,@synchronized块中的代码会加锁保护临界区,使得同时只有一个线程执行其中的代码,当前线程执行完毕之后,其它线程才可以进入执行代码块。NSLock的lock方法和unlock方法之间的部分会加锁保护。

	@synchronized(string) {
            //do something
        }
        
        NSLock *lock = [[NSLock alloc] init];
        [lock lock];
        //do something
        [lock unlock];

2.递归锁

递归锁又成为可重入锁,它是指一个线程可以重复地获取某个锁。递归锁可以使用引用计数的方式实现,获取一次锁,相应的引用计数加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);
}

你可能感兴趣的:(iOS)