美文网首页
iOS 线程(锁 lock)同步方案的性能比较

iOS 线程(锁 lock)同步方案的性能比较

作者: yulekwok | 来源:发表于2019-08-24 00:17 被阅读0次

性能从高到低排序
os_unfair_lock iOS //10 之后才可以使用
OSSpinLock // iOS10 之后不建议使用
dispatch_semaphore // 我个人比较喜欢使用
pthread_mutex // 我个人比较喜欢使用
dispatch_queue(DISPATCH_QUEUE_SERIAL)
NSLock // 封装 pthread_mutex
NSCondition
pthread_mutex(recursive) // 递归锁
NSRecursiveLock
NSConditionLock
@synchronized 可以直接在GNU 里面看相关的代码

多线程学习

技术方案 简介 语言 线程生命周期 使用频率
pthread 一套通用的多线程API 适用于Unix\Linux\Windows等系统 跨平台\可移植 使用难度大 C 程序员管理 几乎不用
NSThread 使用更加面向对象 简单易用,可直接操作线程对象 OC 程序员管理 偶尔使用
GCD 旨在替代NSThread等线程技术 充分利用设备等多核 C 自动管理 经常使用
NSOperation 基于GCD(底层是GCD) 比GCD 多了一些简单实用的功能 实用更加面向对象 OC 自动管理 经常使用

GCD 的常用函数

GCD 队列可以分为2大类

并发队列

可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)

并发功能只能在异步(dispatch_async)函数下才能生效

串行队列

让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

比较容易混淆的专业术语

同步 异步 并发 串行

同步异步主要是影响:能不能开启新的线程

同步:在当前线程中执行任务,不具备开启新的线程的能力 dispatch_sync

异步:在新的线程中执行任务,具备开启新线程的能力 dispatch_async

如果放在了主队列,那么只能在主线程执行

并发和串行

并发多个任务并发(同时)执行 dispatch_get_global_queue(0, 0);

串行一个任务执行完毕后,再执行下一个任务 dispatch_queue_create("que1", DISPATCH_QUEUE_SERIAL);

同步/异步 并发队列 手动创建串行队列 主队列(特殊的串行队列)
同步sync 没有开启新的线程 行执行任务 没有开启新的线程 行执行任务 没有开启新的线程 行执行任务
异步async 开启新的线程 并发执行任务 开启新的线程的线程 串行执行任务 没有开启新的线程 串行执行任务

使用sync 函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"------");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{ // 死锁
        NSLog(@"---1---");
        NSLog(@"%@", [NSThread currentThread]);
    });
    NSLog(@"---2---");
}

线程组

 dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue = dispatch_queue_create("gyule", DISPATCH_QUEUE_CONCURRENT);// 并发
    NSLog(@"------");
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任务1-----%@", [NSThread currentThread]);
        }
        
    });
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任务2---- - %@", [NSThread currentThread]);
        }
    });
    //等前面的执行完成之后再执行下面的任务
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        for (int i = 0; i < 5; i++) {
            // 在主线程执行
            NSLog(@"任务3 -----%@", [NSThread currentThread]);
        }
    });
    //等前面的执行完成之后再执行下面的任务 1 2 会并发,12 结束后 4 5 会并发
    dispatch_group_notify(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任务4 -----%@", [NSThread currentThread]);
        }
    });
    //等前面的执行完成之后再执行下面的任务
    dispatch_group_notify(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任务5 -----%@", [NSThread currentThread]);
        }
    });

线程同步技术(同步就是协同步调,按预定的先后次序进行)

常用的线程同步技术是:加锁

锁:

锁名字 说明
OSSpinLock 自旋锁,等待锁的线程会处于忙等(busy-wait)状态,一直占用CPU资源,目前已经不再安全,可能会出现优先级反转问题
os_unfair_lock 用于取代不安全的OSSpinLock从iOS10 以后开始可以使用,从底层看是线程进行休眠,并非忙等
pthread_mutex 互斥锁,等待锁的线程处于休眠状态

OSSpinLock

#import <libkern/OSAtomic.h>
@property(nonatomic,assign) OSSpinLock lock; // c 语言使用assign 修饰
- (void)lock1 {
    // 初始化锁
    OSSpinLock lock = OS_SPINLOCK_INIT;
    // 加锁
    OSSpinLockLock(&lock);  
     // 尝试加锁
    // bool locked = OSSpinLockTry(&lock);
    // 解锁
    OSSpinLockUnlock(&lock);
}

os_unfair_lock

#import <os/lock.h>
// 结构体 使用assign
@property (nonatomic, assign) os_unfair_lock lock1;
- (void)lock2 {
    // 初始化锁
    os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
    // 加锁
    os_unfair_lock_lock(&lock);
    // 尝试加锁
    bool locked = os_unfair_lock_trylock(&lock);
    // 解锁
    os_unfair_lock_unlock(&lock);
}

pthread_mutex_lock

- (void)lock3 {
    // 静态初始化互斥锁
    //    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t mutex;
    // 初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    //    /*
    //     * Mutex type attributes
    //     */
    //    #define PTHREAD_MUTEX_NORMAL        0 // 常规锁 默认锁
    //    #define PTHREAD_MUTEX_ERRORCHECK    1 // 检查锁
    //    #define PTHREAD_MUTEX_RECURSIVE        2 // 自旋锁
    //    #define PTHREAD_MUTEX_DEFAULT        PTHREAD_MUTEX_NORMAL
  
  // 递归锁:允许同一个线程对一把锁进行重复加锁
  
  
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    // 初始化锁
    pthread_mutex_init(&mutex, &attr);
    // 销毁属性
    pthread_mutexattr_destroy(&attr);
    // 加锁
    pthread_mutex_lock(&mutex);
    // 解锁
    pthread_mutex_unlock(&mutex);
    // 释放锁
    pthread_mutex_destroy(&mutex);
}

使用场景 生产者消费者模式,线程依赖 例如 线程1 等待线程2 结束之后才能执行

-(void)lock4{
    // 条件锁
    
    pthread_cond_t cont;
    pthread_cond_init(&cont,nil);
    // 互斥锁属性
    pthread_mutexattr_t attr;
    // 互斥锁属性初始化
    pthread_mutexattr_init(&attr);
    // 添加属性 递归锁 允许同一个线程对同一把锁进行多次加锁
    /*
     * Mutex type attributes
     */
    // #define PTHREAD_MUTEX_NORMAL        0 // 正常锁
    //    #define PTHREAD_MUTEX_ERRORCHECK    1 // 检查锁
    //    #define PTHREAD_MUTEX_RECURSIVE        2 // 递归锁
    //    #define PTHREAD_MUTEX_DEFAULT        PTHREAD_MUTEX_NORMAL // 默认锁
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,&attr);
    pthread_mutex_lock(&mutex);
    // 睡觉 放开mutex 这把锁 等待 cont 别人放开
    pthread_cond_wait(&cont, &mutex);
    // 唤醒 等待 cont的线程
    pthread_cond_signal(&cont);
    pthread_mutex_unlock(&mutex);
    
    
    
    // 释放 互斥锁
    pthread_mutex_destroy(&mutex);
    // 释放 互斥锁的属性
    pthread_mutexattr_destroy(&attr);
    // 释放条件
    pthread_cond_destroy(&cont);
}

相关文章

网友评论

      本文标题:iOS 线程(锁 lock)同步方案的性能比较

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