进程同步经典问题(生产者-消费者、读写、哲学家)

生产者-消费者问题

要求

  1. 生成者在缓存未满时,可添加数据;
  2. 消费者在缓存未空时,可消费数据;
  3. 缓存同一时刻只有一方在操作。

基本思路

  1. 添加empty信号量,表示缓存未满;
  2. 添加full信号量,表示缓存未空;
  3. 添加mutex互斥量,保证只有一方操作。

代码

#define N 100
typedef int semaphore
semaphore empty = N; // 大小为缓存大小, 可理解为缓存空余大小
semaphore full = 0;  // 初始化为0,保证消费者不会直接执行,可理解为缓存使用大小
semaphore mutex = 1;

void produce()
{
	while(TRUE)
	{
		int data = produceData();
		down(&empty);  // 先确定是否可操作
		down(&mutex);  // 然后在通过互斥量操作,避免死锁
		insert(item);
		up(&mutex);
		up(&full);
	}
}

void consumer()
{
	while(TRUE)
	{
		down(&full);
		down(&mutex);
		int data = removeData();
		consumeData(data);
		up(&mutex);
		up(&empty);
	}
}

* 上述代码引自CyC2018

读写问题

要求

  1. 读写,写写不能同时发生;
  2. 读读之间可以同时发生。

基本思路

  1. 引入资源锁,当首次读出现时,加资源锁,当读全部结束时,解资源锁;
  2. 引入读数量,确定什么时候加(解)资源锁,对于读数量的改变也要在临界区中进行。
  3. 写数据直接,获取资源锁 -> 写操作 -> 释放资源锁。

代码

#define int semaphore;
semaphore count_mutex = 1;
semaphore data_mutex = 1;
int count = 0;

void reader() 
{
	while (TRUE)
	{
		down(&count_mutex);
		count++;
		if (count == 1) {  // 第一个读锁住资源,避免写
			down(&data_mutex);
		}
		up(&count_mutex);
		
		read();
		
		down(&count_mutex);
		count--;
		if (count == 0) {  // 最后一个读解锁资源
			up(&data_mutex);
		}
		up(&count_mutex);
	}
}

void writer()
{
	while(TRUE)
	{
		down(&data_mutex);
		write();
		up(&data_mutex);
	}
}

* 上述代码引自CyC2018

注意:上述方法若是读太多会导致写饿死。此时可以加入队列来解决上述情况,即在读写之间尝试获取队列互斥量,写线程获取了队列信号量之后,读线程获取不到,就不会继续添加 count 了。

哲学家问题

要求

  1. 哲学家有思考和吃饭两个状态,吃饭状态需要两个筷子,即必须获取到左右两边的筷子;
  2. 每个哲学家之间只有一根筷子;

基本思路

  1. 为了避免死锁,每次吃之前都要获取两个筷子,吃完要放下两个筷子,不能单个筷子操作,两个筷子的取放视为原子操作;
  2. 只有在两边都没有进餐的时候,才可以进餐;
  3. 将哲学家分为三个状态,思考状态不需要筷子,进餐状态获取了左右的筷子,饥饿状态表示等待,等待获取筷子。

代码

#define N 5
#define LEFT (i + N - 1) % N
#define RIGHT (i + 1) % N
#define THINK 0
#define EAT 2
#define HUNGRY 3
#define int semaphore;
semaphore state_mutex = 1; // 状态临界区互斥量
int state[N] = {0};  // 哲学家状态
semaphore state_mutex[N] // 每个哲学家一个信号量用作等待

void philosopher(int i) 
{
	while(TRUE)
	{
		think(i);
		take_two(i);
		eat(i);
		put_two(i);
	}
}

void take_two(int i)
{
	down(&state_mutex);  // 准备修改状态
	state[i] = HUNGRY;   // 将状态设置为饥饿
	tryEat(i);          // 尝试获取筷子
	up(&state_mutex);
	down(&state_mutex[i]);  // 若获取成功,不会阻塞,失败则阻塞
}

void put_two(int i) 
{
	down(&state_mutex);  // 准备修改状态
	state[i] = THINK;   // 将状态设置为思考
	tryEat(LEFT);          // 让左边的人尝试获取筷子
	tryEat(RIGHT);          // 让右边的人尝试获取筷子
	up(&state_mutex);
}

void tryEat(int i)
{
	if (state[i] == HUNGRY && state[LEFT] != EAT&& state[RIGHT] != EAT)
	{
		state[i] = EAT;
		up(&state[i]);
	}
}
* 上述代码引自CyC2018
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值