IOS知识积累

iOS 锁 部分四

2020-08-02  本文已影响0人  飞不越疯人院

主要讲解设计多读单写模型pthread_rwlock_t/dispatch_barrier_async的基本用法

常见锁的分类:

iOS 锁 部分一
iOS 锁 部分二
iOS 锁 部分三
iOS 锁 部分四


1. 如果实现一个多读单写的模型

如何实现一个多读单写的模型,需求如下

方案1 读写锁pthrad_rwlock_t

特点

  1. 读取加锁可以同时多个线程进行,写入同时只能一个线程进行, 等待的线程处于休眠状态;
  2. 可能会用到的方法
    2.1 pthread_rwlock_init()初始化一个读写锁;
    2.2 pthread_rwlock_rdlock()读写锁的读取加锁;
    2.3 pthread_rwlock_wrlock()读写锁的写入加锁;
    2.4 pthread_rwlock_unlock()解锁;
    2.5 pthread_rwlock_destroy()销毁锁;
  3. 测试代码如下, 测试代码主要看的是: 打印读取可以同时出现几个, 打印写入同时只会出现一个;
/***********************************pthread_rwlock_t*************************************/
- (void)rwLockType {
    pthread_rwlock_init(&_lock, NULL);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    __weak typeof(self) weakSelf = self;
    for (int i = 0; i < 100; i ++) {
        ///同时创建多个线程进行写入操作
        dispatch_async(queue, ^{
            [weakSelf lockWriteAction];
        });
        dispatch_async(queue, ^{
            [weakSelf lockWriteAction];
        });
        dispatch_async(queue, ^{
            [weakSelf lockWriteAction];
        });
        
        ///同时创建多个线程进行读操作
        dispatch_async(queue, ^{
            [weakSelf lockReadAction];
        });
        dispatch_async(queue, ^{
            [weakSelf lockReadAction];
        });
        dispatch_async(queue, ^{
            [weakSelf lockReadAction];
        });
    }
}
- (void)lockReadAction {
    pthread_rwlock_rdlock(&_lock);
    sleep(1);
    NSLog(@"RWLock Read Action   %@", [NSThread currentThread]);
    pthread_rwlock_unlock(&_lock);
}
- (void)lockWriteAction {
    pthread_rwlock_wrlock(&_lock);
    sleep(1);
    NSLog(@"RWLock Write Action   %@", [NSThread currentThread]);
    pthread_rwlock_unlock(&_lock);
}
- (void)dealloc {
    pthread_rwlock_destroy(&_lock);
}
/***********************************pthread_rwlock_t*************************************/

方案2 异步栅栏 dispath_barrier_async

特点

  1. 传入的并发队列队列必须是手动创建, dispatch_queue_create()方式;
    如果传入串行队列或者通过dispatch_get_global_queue()方式创建, 则dispath_barrier_async的作用就跟dispath_async变得一样;
  2. 可能会用到的方法
    2.1 dispatch_queue_create()创建并发队列;
    2.2 dispatch_barrier_async()异步栅栏;
  3. 测试代码如下, 测试代码主要看的是: 打印读取可以同时出现几个, 打印写入同时只会出现一个;

/*********************************dispatch_barrier_async**********************************/
- (void)barrierAsyncType {
     self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 100; i ++) {
        ///同时创建多个线程进行写入操作
        [self barrierWriteAction];
        [self barrierWriteAction];
        [self barrierWriteAction];
        ///同时创建多个线程进行读取操作
        [self barrierReadAction];
        [self barrierReadAction];
        [self barrierReadAction];
    }
}
- (void)barrierReadAction {
    dispatch_async(self.queue, ^{
     sleep(1);
    NSLog(@"barrier Read Action   %@", [NSThread currentThread]);
    });
 }
- (void)barrierWriteAction {
    dispatch_barrier_async(self.queue, ^{
     sleep(1);
    NSLog(@"barrier Write Action   %@", [NSThread currentThread]);
    });
 }
/*********************************dispatch_barrier_async**********************************/

关于锁定的一些总结

1. 常用的锁的效率排序
  1. os_unfair_lock(iOS10之后)
  2. OSSpinLock(iOS10之前)
  3. dispatch_semaphore(iOS版本兼容性好)
  4. pthread_mutex_t(iOS版本兼容行好)
  5. NSLock( 基于pthread_mutex_t封装)
  6. NSCondition( 基于pthread_mutex_t封装)
  7. pthread_mutex_t(recursive)(递归锁的优先推荐)
  8. NSRecursiveLock(基于pthread_mutex_t封装)
  9. NSConditionLock(基于NSCondition封装)
  10. @synchronized
    10.1 iOS12之前基于pthread_mutex_t封装
    10.2 iOS12之后基于os_unfair_lock封装(iOS12之后它的效率应该不是最低, 应该在3/4左右);
2. 自旋锁和互斥锁的取舍

自旋锁和互斥锁怎么选择, 其实这个问题已经没有什么意义, 因为自旋锁OSSpinLockiOS10之后已经废弃, 而它的替换方案os_unfair_lock是互斥锁;但是我们仍然做一下对比;
自旋锁:

互斥锁:


3. 其他注意点

3.1 加锁和解锁的实现一定要配套出现, 不然就会出现死锁的现象;


文中测试代码
参考文章
objc4源码下载地址
libplatform源码下载地址

上一篇 下一篇

猜你喜欢

热点阅读