简单介绍下iOS下常用的锁操作,加上个人的理解,如有错误欢迎指出:
常用的锁分类:自旋锁,互斥锁,信号量
自旋锁
实现原理应该是全局管理一个锁标志,lock操作会占用锁,如果已经被占用,则会一直循环抢占。unlock会释放锁。
ptheard_lock_t lock; // 类型名是私自起的
// 如果>0则占用锁并做事情,否则继续抢占
lock
if lock > 0 {
lock = 0
do something
} else {
lock()
}
// 释放锁
unlock
lock = 1
自旋锁有个缺点是如果你没有抢占到锁,会一直占用CPU,所以不是个好东西
互斥锁
互斥锁和自旋锁的不同在于如果没抢占到锁,会挂起,不浪费CPU。
那么要实现这种操作就要借助 生产者消费者模型。
生产消费模型先简单介绍下,下边会详细介绍:
基础逻辑是维护一个队列,如果有生产者过来,会存放在队列里,然后让消费者去处理,也就是消费者从队列里拿出并处理消息,生产者向队列加入消息。
ptheard_lock_t lock; // 类型名是私自起的
ptherad_lock_queue_t theradQueue; // 私自命名,生产消费模型的队列
// 如果>0则占用锁并做事情,否则继续抢占
lock
if lock > 0 {
lock = 0
do something
} else {
theradQueue.addThread()
sleep()
}
// 释放锁
unlock
lock = 1
if theradQueue.count > 0 {
// 找到在等待的线程并继续执行
theradQueue.lastObject wakeUp()
}
互斥锁的好处在于,如果没抢占到锁,那我会休息一会,等别人来叫我。节省CPU。(pthread_mutex)
信号量
个人理解信号量是在互斥锁的基础上做了一个扩展,使之能够控制线程并发数:
ptheard_lock_t lock = 10; // 类型名是私自起的
ptherad_lock_queue_t theradQueue; // 私自命名,生产消费模型的队列
// 如果>0则占用锁并做事情,否则继续抢占
lock
if lock > 0 {
lock--
do something
} else {
theradQueue.addThread()
sleep()
}
// 释放锁
unlock
lock++
if theradQueue.count > 0 {
// 找到在等待的线程并继续执行
theradQueue.lastObject wakeUp()
}
这样就可以控制线程并发量了,也就是把锁的变量值控制在一个数,也就是并发数。
生产者消费模型
那么什么是生产消费模型呢?
其实就是建立一个缓冲区,来记录下现在来不及处理,但需要按顺序来处理的queue。
// 为了方便理解 采用部分语言的方式书写
class ptherad_lock_queue_t {
MutableArray *queue = []
void addThread(Thread *thread) {
queue.insertObejctAtIndex(thread, 0)
}
Thread *lastObject() {
return queue.lastObject()
}
}
我们可以把这个理解成一个缓冲区:
当有线程想加锁,但没有抢到时,会加在这个队列里。
当上一个队列释放锁之后,会唤醒队列里出栈的那个。
这样就能保证线程间按顺序执行了。