iOS 底层 day22 多线程 NSConditionLock semaphore @synchronized 多读单写

一、 NSConditionLock

  • NSConditionLock 是对 NSCondition 的进一步封装,可以设置具体的条件值
  • 主要用于处理线程间的依赖
#import "NSConditionLockDemo.h"

@interface NSConditionLockDemo ()
@property(nonatomic, strong)NSConditionLock *conditionLock;
@end

@implementation NSConditionLockDemo
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
    }
    return self;
}
- (void)otherTest {
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        [self __three];
    });
    dispatch_async(queue, ^{
        [self __one];
    });
    dispatch_async(queue, ^{
        [self __two];
    });
    
}
- (void)__one {
    [self.conditionLock lockWhenCondition:1];
    NSLog(@"%s",__func__);
    [self.conditionLock unlockWithCondition:2];
}
- (void)__two {
    [self.conditionLock lockWhenCondition:2];
    NSLog(@"%s",__func__);
    [self.conditionLock unlockWithCondition:3];
}
- (void)__three {
    [self.conditionLock lockWhenCondition:3];
    NSLog(@"%s",__func__);
    [self.conditionLock unlockWithCondition:1];
}

@end

  • 上述代码就能保证_one_two_three这三个任务按顺序执行。

二、 SerialQueue 串行队列

  • 线程同步,目的就是让任务一个个执行。所以我们不一定要用锁来实现,我们用串行队列也是可以的
#import "SerialQueueDemo.h"

@interface SerialQueueDemo ()
@property(nonatomic, strong) dispatch_queue_t serialQueue;
@end

@implementation SerialQueueDemo
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
    }
    return self;
}

- (void)__saleTicket {
    dispatch_sync(self.serialQueue, ^{
        [super __saleTicket];
    });
}
@end

三、 semaphore 信号量

  • semaphore 叫做 信号量
  • 信号量的初始值,可以用来控制线程并发访问的最大数量
  • 信号量的初始值为 1,代表同时值允许 1 条线程访问资源,保证线程同步
  • semaphore 当 value 为 1 时,也可以达到线程同步的效果。
semaphore主要 API
#import "SemaphoreDemo.h"

@interface SemaphoreDemo ()
@property(nonatomic, strong)dispatch_semaphore_t semaphore1;
@property(nonatomic, strong)dispatch_semaphore_t semaphore5;
@end
@implementation SemaphoreDemo
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.semaphore1 = dispatch_semaphore_create(1);
        self.semaphore5 = dispatch_semaphore_create(5);
    }
    return self;
}
- (void)__saleTicket {
    dispatch_semaphore_wait(self.semaphore1, DISPATCH_TIME_FOREVER);
    [super __saleTicket];
    dispatch_semaphore_signal(self.semaphore1);
}

- (void)__test {
    dispatch_semaphore_wait(self.semaphore5, DISPATCH_TIME_FOREVER);
    sleep(2.0);
    NSLog(@"task");
    dispatch_semaphore_signal(self.semaphore5);
}

- (void)otherTest {
    for (int i = 0; i < 20; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__test) object:nil] start];
    }
}
@end

四、 @sychronized

  • @synchronized 是对 mutex递归锁 的封装
  • 源码查看: objc4 中的 objc-sync.mm 文件
  • @synchronized(obj) 内部会生成 obj 对应的递归锁,然后进行加锁、解锁操作
  • 最大有点:使用起来最方便
  • 最大缺点:性能最低
#import "SynchronizedDemo.h"

@implementation SynchronizedDemo
- (void)__saleTicket {
    @synchronized(self){
        [super __saleTicket];
    }
}
- (void)__saveMoney {
    @synchronized([self class]){
        [super __saveMoney];
    }
}
- (void)__drawMoney {
    @synchronized([self class]){
        [super __drawMoney];
    }
}
@end

五、 自旋锁和互斥锁比较

1. 什么情况使用自旋锁比较划算?
  • 预计线程等待锁的时间很短
  • 加锁的代码(临界区)经常被调用,但竞争情况很少发生
  • CPU 资源不紧张
  • 多核处理器
2. 什么情况使用互斥锁比较划算?
  • 预计线程等待锁的时间比较长
  • 单核处理器
  • 临界区有 IO 操作
  • 临界区代码复杂或者循环量大
  • 临界区竞争非常激烈

六、atomic

  • atomic 中文意思 原子性,可以参考源码 objc4objc-accessors.mm
  • atomic 可以用于保证属性 setter、getter 的原子性操作,相当于在 getter、setter 内部添加了线程同步的锁
  • atomic 不可以保证属性的使用过程是线程安全的
  • 相信 iOS 开发我们经常见到 nonatomic ,极少见到 atomic,因为搭载 iOS 设备通常内存都不大,会频繁读取属性,如果是 atomic,就会进行加锁,影响效率。一般用在 mac 项目中。

七、如何在 iOS 中实现 多读单写?(两种方案)

  • 同一时间,只能 1 个线程进行写的操作
  • 同一时间,允许多个线程进行读的操作
  • 同一时间,不允许既有写的操作,又有读的操作
我觉得这个图很经典
1. 使用这个模板代码尝试解决问题?
- (void)otherTest {
    for (int i = 0; i < 10; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
        [[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
        [[[NSThread alloc] initWithTarget:self selector:@selector(__write) object:nil] start];

    }
}
- (void)__read {
    NSLog(@"%s", __func__);
}
- (void)__write {
    NSLog(@"%s___start", __func__);
    sleep(1.0);
    NSLog(@"%s___end", __func__);
}
2. 使用垮平台的 pthread_rwlock_t
  • pthread_rwlock_t 等待锁的线程会进入休眠
#import "PthreadRwlockDemo.h"
#import 

@interface PthreadRwlockDemo ()
@property(nonatomic, assign)pthread_rwlock_t rwlock;
@end

@implementation PthreadRwlockDemo
- (instancetype)init
{
    self = [super init];
    if (self) {
        pthread_rwlock_init(&_rwlock, NULL);
    }
    return self;
}
- (void)otherTest {
    for (int i = 0; i < 10; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
        [[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
        [[[NSThread alloc] initWithTarget:self selector:@selector(__write) object:nil] start];

    }
}
- (void)__read {
    pthread_rwlock_rdlock(&_rwlock);
    NSLog(@"%s", __func__);
    pthread_rwlock_unlock(&_rwlock);
}
- (void)__write {
    pthread_rwlock_wrlock(&_rwlock);
    sleep(1.0);
    NSLog(@"%s", __func__);
    pthread_rwlock_unlock(&_rwlock);
}
- (void)dealloc {
    pthread_rwlock_destroy(&_rwlock);
}
@end
3. 使用 iOS 提供的栅栏函数 dispatch_barrier_async
  • 这个函数传入的并发队列必须是自己通过 dispatch_queue_create 创建的
  • 如果传入的是一个串行或者是一个全局并发队列,那么这个函数便等同于dispatch_async 函数的效果
#import "DispatchBarrierAsyncDemo.h"

@interface DispatchBarrierAsyncDemo ()
@property(nonatomic, strong) dispatch_queue_t queue;
@end

@implementation DispatchBarrierAsyncDemo

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

- (void)otherTest {
    for (int i = 0; i < 10; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
        [[[NSThread alloc] initWithTarget:self selector:@selector(__read) object:nil] start];
        [[[NSThread alloc] initWithTarget:self selector:@selector(__write) object:nil] start];

    }
}
- (void)__read {
    dispatch_async(self.queue, ^{
        NSLog(@"%s", __func__);
    });
}
- (void)__write {
    dispatch_barrier_async(self.queue, ^{
        sleep(1.0);
        NSLog(@"%s", __func__);
    });
}
@end

你可能感兴趣的:(iOS 底层 day22 多线程 NSConditionLock semaphore @synchronized 多读单写)