admin管理员组文章数量:1599533
0 介绍
以前只是会使用Linux下的条件变量pthread_cond_t,知道它的作用是配合互斥锁解决并发编程的同步问题,没有思考过它的实现原理,今天学习了清华大学陈渝老师的操作系统网课,总算是明白了,特此记录。
1 实现
条件变量是一种等待机制,每一个条件变量对应一个等待原因与等待队列。一般对于条件变量会有两种操作:
- wait操作 : 将自己阻塞在等待队列里,唤醒一个等待者或者开放锁的互斥访问
- singal 操作 : 唤醒一个等待的线程(等待队列为空的话什么也不做)
下面看看它的伪码描述,两个变量一个描述在等待队列的线程数,一个就是等待队列:
class Condition
{
int numWaiting = 0; //在队列中等待的线程数
WaitQueue q; //等待队列
};
对于wait操作来说,首先给numWaiting加1,然后将当前线程加入等待队列里,然后释放开锁,schedule将放开cpu给其他线程,回来之后再次尝试获取锁。
Condition::Wait(lock)
{
++numWaiting;
Add this thread to WaitQueue q;
release(lock);
schedule(); //调度机制
acquire(lock);
}
对于singal操作来说,则如果等待队列中有线程的话,将它取出唤醒,numWaiting减一即可。
Condition::Singal()
{
if(numWaiting > 0)
{
remove t from q;
wakeup(q);
--numWaiting;
}
}
2 应用
懂了这些实现后,看看如何利用前面的知识解决经典的生产者消费者问题。我们假定有多个生产者和多个消费者,生产者往buffer中加入产品,消费者从buffer中拿走产品。buffer的大小有上限,设为n,也就是说当buffer中的产品为n时生产者不能继续在buffer中添加商品,为0时消费者不能继续在buffer中拿走商品。
不难知道我们需要一个锁Lock,两个条件变量notEmpty和notFull分别用于指示消费者和生产者,count是目前buffer中的产品数。
class BoundedQueue
{
Lock lock;
count = 0;
Condition notEmpty,notFull;
};
对于生产者来说,其执行的操作如下:首先活动锁之后,检查buffer是否满了,如果满了,则执行wait。添加好商品后,执行notEmpty的singal,唤醒一个消费者线程消费。
BoundedQueue::deposit
{
acquire(lock);
while(count == n)
notFull.wait();
add c to the buffer;
++count;
notEmpty.singal();
release(lock);
}
对于消费者来说,其操作和生产者差不多:
BoundedQueue::remove()
{
acquire(lock);
while(count == n)
notEmpty.wait();
remove c from buffer;
--count;
notFull.Singal();
release(lock);
}
本文标签: 变量原理条件conditionvariables
版权声明:本文标题:并发编程中条件变量(condition variables)实现原理 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1728323619a1154151.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论