IOS多线程中的锁

212 阅读2分钟

1. 自旋锁 spinlock/cas

当访问另一个线程锁定的部分时忙等待,一直占用CPU资源, 当锁定部分的代码执行很快时适合用自旋锁.

2. 互斥锁 os_unfair_lock/pthread_mutex/NSLock

没有获取到锁时会让当前线程进入休眠状态.

  • NSLock 封装了pthread_mutex的PTHREAD_MUTEX_NORMAL 模式
  • NSRecursiveLock 封装了pthread_mutex的PTHREAD_MUTEX_RECURSIVE模式

3. 递归锁

同一线程访问一段代码,如果是加锁的可以继续加锁.不同线程发现有锁要等待所有锁解开之后才可以继续执行

4. 条件锁

一定条件下,让其等待休眠并放开锁,等接收到信号或者广播,会从新唤起线程,并重新加锁. NSCondition支持lock/unlock/wait阻塞/signal唤醒操作.是对pthread_cond_wait,pthread_cond_signal,pthread_cond_broadcast 的包装. NSConditionLock封装了NSCondition,不需要wait/signal,接受条件(int值),例:

//produce
dispatch_exe(produce_thread){
    while(true){
      condition.lock
      if(full){ ondition.wait //block}
      // ... produce()
      condition.signal
      condition.unlock
      }
}

//consume
dispatch_exe(consume_thread){
  while(true){
      condition.lock
      if(empty){condition.wait}
      //...consume()
      condition.signal
      condition.unlock
  }
}

5. @synchronized(锁对象)

底层封装的pthread_mutex的PTHREAD_MUTEX_RECURSIVE 模式,锁对象来表示是否为同一把锁

6. dispatch_semaphore

//示例1:阻塞发请求的线程
dispatch_exe(queue){
   sem = dispatch_semaphore_create(0)
   dispatch_exe_async(netrequest)^{ signal(sem)}
   wait(sem)
}
    
//示例2: 控制多个线程并发
sem = dispatch_semaphore_create(n)
   for(i:=0;i<n;i++){
   
       dispatch_exe(){
        wait(sem)
        // do something in per thread
        signal(sem)
       }
}
    

优先级反转

  • 原因
    优先级 task1>task2>task3, 有一个互斥访问的稀缺资源S.
    1. task3正在执行,申请到了S. task1抢占task3并申请资源S,发现已经被占用,所以task3恢复运行.
    2. task2抢占task3,由于不需要访问S, task2先执行,task执行完 task3恢复
    3. task3释放资源S, task1抢占 task1执行. 最后执行顺序变成了task2->task1->task3
  • 解决方案
    task3使用S期间, task1抢占执行申请资源S时,比较task1/task3优先级,如果task1>task3,临时将task3提升到访问S的最高优先级,释放完S后再将task3优先级调整回来