【5】信号量机制

1、整型信号量

信号量定义为一个整型量S,S≤0 表示该资源已被占用;S≥0 表示资源可用
进程企图进入临界区时,S≤0 禁止进入,S≥0 可以进入

  • wait 操作 ---- P操作
  • signal操作 ---- V操作

存在问题:S<=0时,会让进程(线程)处于“忙等”状态

2、记录型信号量semaphore

typedef struct {
	int value;
	list<PROC> L;	//阻塞进程队列
}semaphore;
  • value>0 时,value为资源可用数目
  • value<0 时,|value|为已阻塞进程的数目
  • L为阻塞进程队列首指针

3、AND信号量

申请n种资源,每种1个,或者全部分配,或者不分配,避免死锁

4、信号量集

申请n种资源,资源S_i(1 <= i <= n)申请d_i个资源且资源个数下限为t_i,或者全部分配,或者不分配,避免死锁

  • Swait(S_1, 1, 1, …, S_n, 1, 1),即所有t_i、d_i都等于1,等价于AND信号量的Swait(S_1, …, S_n)
  • Swait(S, 1, 1):退化为记录型信号量,但执行效率低
  • Swait(S, 1, 0):特殊信号量,S.value>=1 时允许多进程进入临界区;S<=0 时阻止所有进程进入临界区,相等于一个开关
    信号量策略 :
  • 寻找临界资源
  • 定义信号量
  • 使用前申请
  • 使用后释放

5、生产者-消费者问题

多生产者-多消费者问题信号量:

  • space,存储位置,初值N;
  • prod,产品,初值0;
  • buf,缓冲区,初值1

循环创建M个生产者和消费者线程

void * producer(void *p) {
	while(1) {
		sem_wait(&space);		//申请存储位置资源
		sem_wait(&buf);			//获取缓冲区控制权
		printf("Put a producer into Buffer[%d]!\n",in);
		in = (in + 1) % N;		//将产品放到队尾位置并修改队尾指针
		sem_post(&prod);			//释放产品资源
		sem_post(&buf);			//释放缓冲区资源
	}
	return NULL;
}
void * consumer(void *p) {
	while(1) {
		sem_wait(&prod);		//申请产品资源
		sem_wait(&buf);			//获取缓冲区控制权
		printf("Get a producer from Buffer[%d]!\n",out);
		out = (out + 1) % N;		//从队头位置取产品并修改队头指针
		sem_post(&space);			//释放存储位置资源
		sem_post(&buf);			//释放缓冲区资源
	}
	return NULL;
}

in(队尾位置) 和 out(队头位置)为共享变量,属于临界资源(效率低下)


优化策略

信号量:

  • space:存储位置,初值N
  • prod:产品,初值0
  • sin:队尾,初值1
  • sout:队头,初值1

允许一个消费者和一个生产者同时在缓冲区放产品和取产品

6、读者-写者问题

数据集被多个并发进程(线程)共享,一些进程(线程)只读取数据集内容(读者),而另一些进程(线程)则只修改数据集内容(写者)

“读—写”互斥,“写—写”互斥,“读—读”允许

变量:readcount,读者数,初值0(共享变量,临界资源)

信号量:

  • sdata,数据集,初值1;
  • srcount,读者数变量,初值1;(实现对readcount的互斥访问)

第一个读者抢占数据集,最后一个离开释放数据集
读者-写者问题


读者-写者问题(写者优先)

信号量sread:读者许可资源,初值为N(读者上限)

void * writer(void *p) {
	Swait(sdata, 1, 1);		//申请数据集操作
	Swait(sread, N, 0);		//等待所有读者离开
	/*Writing dataset ...*/
	Ssignal(sdata, 1);			//释放数据集资源
	return NULL;
}
void * reader(void *p) {
	Swait(sdata, 1, 0, sread, 1, 1);		//判断数据集是否被写者占用,并申请1个读者许可资源
	/*Reading dataset ...*/
	Ssignal(sread, 1);			//释放1个读者许可资源
	return NULL;
}

7、哲学家进餐问题

哲学家进餐所有哲学家都在占据右侧叉子的情况下,被阻塞起来等待自己左侧的叉子,谁也无法继续向前执行,哲学家线程将全部处于阻塞状态,永远不会被唤醒,这种状态被称为死锁
死锁


方案1
偶数编号哲学家先拿右侧叉子,再拿左侧叉子
奇数编号哲学家先拿左侧叉子,再拿右侧叉子

方案2
4号哲学家先拿左侧0号叉子,再拿右侧4号叉子

方案3(ADD型信号量)
同时申请左侧和右侧叉子资源

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值