多线程(2)线程锁

按照性能依次排序

  • OSSpinLock自旋锁
  • os_unfair_lock互斥锁
  • pthread_mutex递归锁
  • pthread_mutex条件锁
  • dispatch_semaphore信号量
  • NSLock
  • NSRecursiveLock
  • NSCondition
  • NSConditionLock
  • @synchronized

两种读写锁
pthread_rwlock读写锁
dispatch_barrier_async异步栅栏

OSSpinLock

  • OSSpinLock叫做自旋锁,等待锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源
  • 目前已经不再安全,可能会出现优先级反转问题
  • 如果等待锁的线程优先级较高,它会一直占用着CPU资源,优先级低的线程就无法释放锁
    1
    2
    3
    4
    5
    6
    7
    8
    #import <libkern/OSAtomic.h>
    //新建锁
    OSSpinLock lock = OS_SPINLOCK_INIT;
    //加锁
    OSSpinLockLock(&lock);
    //处理任务...
    //解锁
    OSSpinLockUnlock(&lock);

os_unfair_lock

  • os_unfair_lock用于取代不安全的OSSpinLock ,从iOS10开始才支持
  • 从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #import <libkern/OSAtomic.h>
    //新建锁
    os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
    //尝试加锁
    os_unfair_lock_trylock(&lock)
    //加锁
    os_unfair_lock_lock(&lock);
    //处理任务...
    //解锁
    os_unfair_lock_unlock(&lock);

pthread_mutex

  • mutex叫做互斥锁,等待锁的线程会处于休眠状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //其中锁的类型有四种
    #define PTHREAD_MUTEX_NORMAL 0 //一般的锁
    #define PTHREAD_MUTEX_ERRORCHECK 1 // 错误检查
    #define PTHREAD_MUTEX_RECURSIVE 2 //递归锁
    #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL //默认
    #import <pthread.h>
    pthread_mutex_t mutex;
    //初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    //初始化锁
    pthread_mutex_init(&mutex, &attr);
    //尝试加锁
    pthread_mutex_trylock(&mutex);
    //加锁
    pthread_mutex_lock(&mutex);
    //解锁
    pthread_mutex_unlock(&mutex);
    // 销毁属性
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(&mutex);

pthread_mutex – 递归锁

  • 允许同一个线程对一把锁进行重复加锁,防止死锁
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #import <pthread.h>
    pthread_mutex_t mutex;
    //初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    //初始化锁
    pthread_mutex_init(&mutex, &attr);
    //尝试加锁
    pthread_mutex_trylock(&mutex);
    //加锁
    pthread_mutex_lock(&mutex);
    //解锁
    pthread_mutex_unlock(&mutex);
    // 销毁属性
    pthread_mutexattr_destroy(&attr);
    pthread_mutex_destroy(&mutex);

pthread_mutex - 条件锁

  • pthread_cond_wait(&_cond, &_mutex)进入休眠,放开mutex锁,被唤醒后,会再次对mutex加锁
  • pthread_cond_signal(&_cond)激活一个等待该条件的线程
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    #import "YZMutexCondLock.h"
    #import <pthread.h>

    @interface YZMutexCondLock()
    @property (assign, nonatomic) pthread_mutex_t mutex; // 锁
    @property (assign, nonatomic) pthread_cond_t cond; //条件
    @property (strong, nonatomic) NSMutableArray *data; //数据源
    @end

    @implementation YZMutexCondLock
    - (instancetype)init {
    if (self = [super init]) {
    // 初始化属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    // 初始化锁
    pthread_mutex_init(&_mutex, &attr);
    // 销毁属性
    pthread_mutexattr_destroy(&attr);

    // 初始化条件
    pthread_cond_init(&_cond, NULL);

    self.data = [NSMutableArray array];
    }
    return self;
    }

    - (void)otherTest {
    [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
    [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
    }

    //线程1 删除数组中的元素
    - (void)__remove {
    pthread_mutex_lock(&_mutex);
    if (self.data.count == 0) {
    // 数据为空就等待(进入休眠,放开mutex锁,被唤醒后,会再次对mutex加锁)
    NSLog(@"__remove - 等待");
    pthread_cond_wait(&_cond, &_mutex);
    }
    [self.data removeLastObject];
    NSLog(@"删除了元素");
    pthread_mutex_unlock(&_mutex);
    }

    //线程2 往数组中添加元素
    - (void)__add {
    pthread_mutex_lock(&_mutex);
    sleep(1);
    [self.data addObject:@"Test"];
    NSLog(@"添加了元素");
    // 激活一个等待该条件的线程
    pthread_cond_signal(&_cond);
    // 激活所有等待该条件的线程
    // pthread_cond_broadcast(&_cond);
    pthread_mutex_unlock(&_mutex);
    }

    - (void)dealloc {
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
    }
    @end

NSLock锁

  • NSLock是对mutex普通锁的封装
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #import "YZNSLock.h"

    @interface YZNSLock()
    @property (nonatomic,strong) NSLock *lock;
    @end

    @implementation YZNSLock
    - (instancetype)init {
    self = [super init];
    if (self) {
    self.lock =[[NSLock alloc] init];
    }
    return self;
    }
    - (void)__saveMoney {
    [self.lock lock];
    [super __saveMoney];
    [self.lock unlock];
    }
    - (void)__drawMoney {
    [self.lock lock];
    [super __drawMoney];
    [self.lock unlock];
    }
    @end

NSRecursiveLock锁

  • NSRecursiveLock也是对mutex递归锁的封装,API跟NSLock基本一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #import "YZNSRecursiveLock.h"

    @interface YZNSRecursiveLock()
    @property (nonatomic,strong) NSRecursiveLock *lock;
    @end

    @implementation YZNSRecursiveLock
    - (instancetype)init {
    self = [super init];
    if (self) {
    self.lock =[[NSRecursiveLock alloc] init];
    }
    return self;
    }
    - (void)__saveMoney {
    [self.lock lock];
    [super __saveMoney];
    [self.lock unlock];
    }

    - (void)__drawMoney {
    [self.lock lock];
    [super __drawMoney];
    [self.lock unlock];
    }
    @end

NSCondition条件锁

  • NSCondition是对mutexcond的封装
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #import "YZNSCondition.h"
    @interface YZNSCondition()
    @property (strong, nonatomic) NSCondition *condition;
    @property (strong, nonatomic) NSMutableArray *data;
    @end
    @implementation YZNSCondition

    - (instancetype)init {
    if (self = [super init]) {
    self.condition = [[NSCondition alloc] init];
    self.data = [NSMutableArray array];
    }
    return self;
    }

    - (void)otherTest {
    [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];

    [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
    }
    // 生产者-消费者模式
    // 线程1
    // 删除数组中的元素
    - (void)__remove {
    [self.condition lock];
    if (self.data.count == 0) {
    // 数据为空就等待(进入休眠,放开锁,被唤醒后,会再次对mutex加锁)
    NSLog(@"__remove - 等待");
    [self.condition wait];
    }
    [self.data removeLastObject];
    NSLog(@"删除了元素");
    [self.condition unlock];
    }
    // 线程2
    // 往数组中添加元素
    - (void)__add {
    [self.condition lock];
    sleep(1);
    [self.data addObject:@"Test"];
    NSLog(@"添加了元素");
    // 激活一个等待该条件的线程
    [self.condition signal];
    // 激活所有等待该条件的线程
    // [self.condition broadcast];
    [self.condition unlock];
    }
    @end

NSConditionLock

  • NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
        #import "YZNSConditionLock.h"
    @interface YZNSConditionLock()
    @end

    @implementation YZNSConditionLock

    - (void)otherTest {
    //主线程中
    NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:0];
    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [lock lockWhenCondition:2];
    NSLog(@"线程1");
    sleep(2);
    NSLog(@"线程1解锁成功");
    [lock unlockWithCondition:3];
    });

    //线程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [lock lockWhenCondition:0];
    NSLog(@"线程2");
    sleep(3);
    NSLog(@"线程2解锁成功");
    [lock unlockWithCondition:1];
    });

    //线程3
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [lock lockWhenCondition:3];
    NSLog(@"线程3");
    sleep(3);
    NSLog(@"线程3解锁成功");
    [lock unlockWithCondition:4];
    });

    //线程4
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [lock lockWhenCondition:1];
    NSLog(@"线程4");
    sleep(2);
    NSLog(@"线程4解锁成功");
    [lock unlockWithCondition:2];
    });

    }
    @end
    ```
    # dispatch_semaphore信号量
    - 信号量的初始值,可以用来控制线程并发访问的最大数量,信号量的初始值为1,代表同时只允许1条线程访问资源,保证线程同步
    ``` objectivec
    #import "YZSemaphore.h"
    @interface YZSemaphore()
    @property (strong, nonatomic) dispatch_semaphore_t moneySemaphore;
    @end

    @implementation YZSemaphore
    - (instancetype)init {
    if (self = [super init]) {
    self.moneySemaphore = dispatch_semaphore_create(1);
    }
    return self;
    }

    - (void)__drawMoney {
    dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
    [super __drawMoney];
    dispatch_semaphore_signal(self.moneySemaphore);
    }

    - (void)__saveMoney {
    dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
    [super __saveMoney];
    dispatch_semaphore_signal(self.moneySemaphore);
    }

synchronized

  • @synchronized是对mutex递归锁的封装
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #import "YZSynchronized.h"
    @interface YZSynchronized()
    @end

    @implementation YZSynchronized
    - (void)__saveMoney {
    @synchronized (self) {
    [super __saveMoney];
    }
    }

    - (void)__drawMoney {
    @synchronized (self) {
    [super __drawMoney];
    }
    }
    @end

pthread_rwlock读写锁

  • 读写锁是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁。多读者锁,“push lock”) 用于解决读写问题。读操作可并发重入,写操作是互斥的。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    #import "YZRwlock.h"
    #import <pthread.h>
    @interface YZRwlock()
    @property (assign, nonatomic) pthread_rwlock_t lock;
    @end

    @implementation YZRwlock
    - (instancetype)init {
    self = [super init];
    if (self) {
    // 初始化锁
    pthread_rwlock_init(&_lock, NULL);
    }
    return self;
    }

    - (void)otherTest{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    for (int i = 0; i < 3; i++) {
    dispatch_async(queue, ^{
    [self write];
    [self read];
    });
    }
    for (int i = 0; i < 3; i++) {
    dispatch_async(queue, ^{
    [self write];
    });
    }
    }

    - (void)read {
    pthread_rwlock_rdlock(&_lock);
    sleep(1);
    NSLog(@"%s", __func__);
    pthread_rwlock_unlock(&_lock);
    }

    - (void)write {
    pthread_rwlock_wrlock(&_lock);
    sleep(1);
    NSLog(@"%s", __func__);
    pthread_rwlock_unlock(&_lock);
    }

    - (void)dealloc {
    pthread_rwlock_destroy(&_lock);
    }
    @end

dispatch_barrier_async异步栅栏实现读写锁

  • 打印完write之后,方法每次都是一个一个执行的,而read是可以同时执行的,但是遇到写的操作,就会把其他读或者写都会暂停,也就是说起到了栅栏的作用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #import "YZBarrier.h"
    @interface YZBarrier ()
    @property (strong, nonatomic) dispatch_queue_t queue;
    @end
    @implementation YZBarrier
    - (void)otherTest{
    // 初始化队列
    self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 3; i++) {
    // 读
    dispatch_async(self.queue, ^{
    [self read];
    });
    // 写
    dispatch_barrier_async(self.queue, ^{
    [self write];
    });
    // 读
    dispatch_async(self.queue, ^{
    [self read];
    });
    // 读
    dispatch_async(self.queue, ^{
    [self read];
    });
    }
    }

    - (void)read {
    sleep(1);
    NSLog(@"read");
    }

    - (void)write {
    sleep(1);
    NSLog(@"write");
    }
    @end