摘要
关于条件变量本人探究好久了,翻查很多博客书籍,都是说它能够弥补互斥锁不足,能够避免竞争,减少cpu的浪费。但是why? 一直没有找到自己想要的答案。最近比较理解了它。
为什么说条件变量要和互斥锁使用。
我们在生产者、消费者问题会遇到这样一种情况——消费者和生产者共同竞争互斥锁。当消费者远大于生产者时,此时若产品为0,但是每个消费者都去抢锁,抢到后发现没有产品,又释放,接着又被其他消费者抢到,又释放…而我们的生产者在旁边干着急。获取锁释放锁又涉及内核操作,由用户态进入内核态花费大量时间。
从图中我们看到,消费者和生产者处于竞争中,但是没有产品,他们处于盲目的竞争,而且浪费时间,我们需要一个管理人员来管理锁,如果没有产品就设置一个标识,表示没有产品,请生产者优先,各位消费者请排队等待。当生产好了,管理员设置标志,让消费者来。
这个管理员就是条件变量,这样优势就体现出来了:能够弥补互斥锁不足,能够避免竞争,减少cpu的浪费。
代码实现
//线程同步必然离不开同步原语,而队列时同步原语的基础
ThreadQueue {
var queue: List of Thread;
sleep() {
enqueue current thread;
put current thread to sleep;
}
wake() {
if (queue not empty) {
dequeue thread;
wake thread;
}
}
wake-all() {
while (queue not empty)
wake();
}
}
/*锁的实现是通过队列实现的,当锁被使用了,就会进入队列并阻塞,
放弃对cpu的竞争*/
Lock {
var isHeld: boolean;
var waitQueue: ThreadQueue;
acquire() {
DisableInterrupts() /*单处理器通过禁用中断来避免竞争条件
的发生,当中断禁止后,线程切换会被阻止。*/
while (isHeld)
waitQueue.sleep();
isHeld = true;
RestoreInterrupts()
}
release() {
DisableInterrupts()
isHeld = false;
waitQueue.wake();
RestoreInterrupts()
}
}
//条件变量时管理员,拥有对锁的管理权,所以要将锁传递给它。同时拥有
队列管理阻塞线程。
Condition(lock) {
var lock: Lock;
var waitQueue: ThreadQueue;
wait() {
DisableInterrupts()
lock.release()
waitQueue.sleep() //通过条件变量阻塞
lock.acquire()
RestoreInterrupts()
}
signal() {
DisableInterrupts()
waitQueue.wake();
RestoreInterrupts()
}
broadcast() {
DisableInterrupts()
waitQueue.wake-all();
RestoreInterrupts()
}
}
源码参考:https://people.eecs.berkeley.edu/~kubitron/courses/cs162-F06/hand-outs/synch.html