多线程-锁

2019-04-01  本文已影响0人  Michael_涵

Quick Start Guide

  1. @synchronized
  2. NSLock 对象锁
  3. NSRecursiveLock 递归锁
  4. NSConditionLock 条件锁
  5. pthread_mutex 互斥锁
  6. dispatch_semaphore 信号量锁
  7. OSSpinLock

性能对比

这里只能反应单线程情况,不能反映多线程下的实际性能

2208956-4a024a1c6c6214db.png

Getting Started

1. @synchronized

@synchronized(obj) {
  //这里obj指oc对象,一般为self
}

注意:加锁的代码量要少,oc对象在多个线程都是同一个对象

2. NSLock

//创建锁
NSLock *lock = [[NSLock alloc] init];
...
[lock lock];
//逻辑处理
[lock unlock];

注意:lock不能多次调用,会造成死锁

3. NSRecursiveLock

//死锁-递归
NSLock *lock = [[NSLock alloc] init];
dispatch_async(self.queue, ^{
  static void (^method)(int value);
  method = ^(int number) {
      [lock lock];
      //条件
      method(number)
      [lock unlock];
  };
  method(10);
});

//正确使用-递归
NSLock *lock = [[NSRecursiveLock alloc] init];
__block int num = 10;
dispatch_async(self.queue, ^{
  static void (^method)(int value);
  method = ^(int number) {
      [lock lock];
      //条件
      method(--number)
      [lock unlock];
  };
  method(num);
});

NSRecursiveLock在递归或者循环内(同一线程)使用不会造成死锁

4. NSConditionLock

NSConditionLock *lock = [[NSConditionLock alloc] init];

//线程1
dispatch_async(self.queue, ^{
  for (int i=0;i<10;i++) {
    [lock lock];
    NSLog(@"%d",i);
    [lock unlockWithCondition:5];
  }
});
//线程2
dispatch_async(self.queue, ^{
  [lock lockWhenCondition:5];
  [lock unlock];
});

5. pthread_mutex

//引用
#include <pthread.h>

//通过设置attr类型可以设置递归锁,互斥锁等
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL)

__block pthread_mutex_t mutex;
pthread_mutex_init(&mutex,&attr);

dispatch_async(self.queue, ^{
  pthread_mutex_lock(&mutex);
  NSLog(@"thread 1");
  pthread_mutex_unlock(&mutex);
});

dispatch_async(self.queue, ^{
  pthread_mutex_lock(&mutex);
  NSLog(@"thread 2");
  pthread_mutex_unlock(&mutex);
});

此方法比较基础,如NSLock,NSConditionLock,,NSRecursiveLock底层实现都是用此方法实现

6. dispatch_semaphore

//创建信号量,并设置初始信号总量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_queue_create("testqueue", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue, ^{
   //模拟耗时操作
   [NSThread sleepForTimeInterval:2];
  //使总信号量减1,当信号总量为0时会一直等待,否则正常执行
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  NSLog(@"thread 1");
  //发送一个信号,让信号总量加1
  dispatch_semaphore_signal(semaphore);
});

dispatch_async(queue, ^{
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  NSLog(@"thread 2");
  dispatch_semaphore_signal(semaphore);
});

7. OSSpinLock

//创建锁
lock = OS_SPINLOCK_INIT;
...
//加锁
OSSpinLockLock(&lock);
...
//解锁
OSSpinLockUnlock(&lock);

不推荐使用,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。ios 10以后可以使用os_unfair_lock代替OSSpinLock

上一篇 下一篇

猜你喜欢

热点阅读