iOS 锁 部分四

作者: 飞不越疯人院 | 来源:发表于2020-08-02 09:55 被阅读0次

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

常见锁的分类:

  • 自旋锁OSSpinLock
  • 互斥锁os_unfair_lock
  • 互斥/递归/条件锁pthread_mutex_t
  • 互斥锁NSLock
  • 递归锁NSRecursiveLock
  • 条件锁NSCondition
  • 条件锁NSConditionLock
  • 递归锁 @synchronized
  • 信号量semaphore
  • 读写锁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是互斥锁;但是我们仍然做一下对比;
自旋锁:

  • 预计线程需要等待的时间较短;
  • 多核处理器;
  • CPU的资源不紧张;

互斥锁:

  • 预计线程需要等待的时间较长;
  • 单核处理器;
  • 临界区(加锁解锁之间部分)有IO操作;
  • 临界区的较为复杂和循环量比较大;

3. 其他注意点

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


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

相关文章

  • iOS 锁 部分四

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

  • iOS 锁 部分三

    主要讲解锁@synchronized/dispatch_semaphore_t的基本用法 文中使用的 objc4源...

  • iOS 锁 部分二

    主要讲解NSLock/NSCondition/NSRecursiveLock/锁的基本用法 常见锁的分类: 自旋锁...

  • iOS 锁 部分一

    主要讲解OSSpinLock/os_unfair_lock/pthread_mutex_t锁的基本用法 常见锁的分...

  • iOS锁系列-目录

    1、 iOS锁系列-NSLock对象锁2、iOS锁系列-NSConditionLock条件锁3、iOS锁系列-NS...

  • 起底多线程同步锁(iOS)

    起底多线程同步锁(iOS) 起底多线程同步锁(iOS)

  • iOS 中常见的几种锁-代码示例

    iOS 中常见的几种锁-代码示例 iOS 中常见的几种锁-代码示例

  • OC--各种线程锁

    参考:正确使用多线程同步锁@synchronized()iOS中的锁iOS多线程安全详解iOS 常见知识点(三):...

  • iOS Foundation 中的线程锁

    前言 锁是线程编程的基本同步工具。锁使您能够轻松地保护大部分代码,从而确保该代码的正确性。OS X 和 iOS ...

  • iOS开发之路---我的6月面试总结

    第一部分:基础知识 1.oc中的各种锁。为什么有效率高低之分? 锁是线程编程同步工具的基础。iOS开发中常用的锁有...

网友评论

    本文标题:iOS 锁 部分四

    本文链接:https://www.haomeiwen.com/subject/kvijrktx.html