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 锁 部分四

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