并发编程中条件变量(condition variables)实现原理

0 介绍

以前只是会使用Linux下的条件变量pthread_cond_t,知道它的作用是配合互斥锁解决并发编程的同步问题,没有思考过它的实现原理,今天学习了清华大学陈渝老师的操作系统网课,总算是明白了,特此记录。

1 实现

条件变量是一种等待机制,每一个条件变量对应一个等待原因与等待队列。一般对于条件变量会有两种操作:

  1. wait操作 : 将自己阻塞在等待队列里,唤醒一个等待者或者开放锁的互斥访问
  2. 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);
}
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值