1.    实验内容简介

抽烟者问题。假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地供应所有三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过程重复进行。  请用信号量机制编程,实现该问题要求的功能。

2.    程序设计思路

主体设计为三大函数,申请(wait)释放(signal)提供(provide),申请和释放函数调用接口为提供资源的进程判定以及获取资源的进程判定,提供函数的调用接口为提供资源的进程判定。

提供资源的进程设计为一个struct,包含随机数,提供3种资源的3种组合方式offer,表示对应人员得到资源,以及进程完毕应答。

获取资源的进程设计为一个struct,包含一个数字num代表吸烟者,以及申请资源的信号量。

主程序的设计为根据之前的struct创建提供资源的进程后,将随机数判定归1,其他归0,再创建获取资源的进程,将num标号123,再将申请资源的信号量判定归0。

之后循环10次输出,对3个smoker各进行一次wait和signal,如果此时提供的资源正好对应自己,那么输出该smoker吸烟,其他人没得到信号量为1,所以不吸烟。

3.    算法分析与设计

1)    申请函数

首先对smoker进行选择,对于每一个smoker判断该次提供的资源是否是自己需要的,如果是则将自己的signal信号修正为1,如果不是输出自己没有得到相应的资源。

2)    释放函数

首先选择smoker,对于每一个smoker判断自己的signal信号是否为1,如果是则输出该smoker开始吸烟,并且修正提供资源信号为0,修正自己的signal判定为0,并将其进程完毕信号修正为1;否,则输出其没有得到相应资源,无其他修正。

3)    提供函数

首先对random随机操作,然后根据进程完毕信号是否为1,正确则选择smoker,对随机操作对应的人提供资源,即将其offer值设定为1,表示得到了资源。

4.    数据结构设计

提供资源的进程设计为一个struct,包含随机数,提供3种资源的3种组合方式offer,表示对应人员得到资源,以及进程完毕应答。

获取资源的进程设计为一个struct,包含一个数字num代表吸烟者,以及申请资源的信号量。

5.    系统实现(系统架构,操作系统运用,数据库运用等)

本项目中未使用。

6.    测试结果

结果运行良好。

7.    源代码

#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include<string>
#include <stack>
#include <vector>
#include <deque>
#include<stdlib.h>
#include <algorithm>
#pragma warning (disable: 4996)
using namespace std;
typedef struct semaphore {
	int random;//存储随机数,用于选择提供资源的类型
	int offer1;//对应烟草和纸的组合
	int offer2;//对应烟草和胶水的组合
	int offer3;//对应胶水和纸的组合
	int finish;//对应进程执行完毕后的应答
}semaphore;

typedef struct Smoker {
	int num;
	int sign;
}Smoker;
//申请资源
int wait(semaphore* s, Smoker* sm) {
	switch (sm->num) {
	case 1:
		if (s->offer1 == 1) {
			//表示1号进程得到想要的资源
			sm->sign = 1;//表示1号进程申请到资源
			printf("%d号进程申请到需要的资源...\n", sm->num);
			break;
		}
		else {
			printf("%d号进程没有申请到需要的资源...\n", sm->num);
			break;
		}
	case 2:
		if (s->offer2 == 1) {
			//表示1号进程得到想要的资源
			sm->sign = 1;//表示1号进程申请到资源
			printf("%d号进程申请到需要的资源...\n", sm->num);
			break;
		}
		else {
			printf("%d号进程没有申请到需要的资源...\n", sm->num);
			break;
		}
	case 3:
		if (s->offer3 == 1) {
			//表示1号进程得到想要的资源
			sm->sign = 1;//表示1号进程申请到资源
			printf("%d号进程申请到需要的资源...\n", sm->num);
			break;
		}
		else {
			printf("%d号进程没有申请到需要的资源...\n", sm->num);
			break;
		}
	}
	return 0;
}
//释放资源
int signal(semaphore* s, Smoker* sm) {
	switch (sm->num) {
	case 1:
		if (sm->sign == 1) {
			printf("%d号吸烟者得到资源开始吸烟...\n", sm->num);
			s->finish = 1;
			s->offer1 = 0;
			sm->sign = 0;
			printf("%d号吸烟者抽烟完成,并将烟草和纸用完\n", sm->num);
			break;
		}
		else {
			printf("%d号吸烟者没有得到资源,不能吸烟...\n", sm->num);
			break;
		}
	case 2:
		if (sm->sign == 1) {
			printf("%d号吸烟者得到资源开始吸烟...\n", sm->num);
			s->finish = 1;
			s->offer2 = 0;
			sm->sign = 0;
			printf("%d号吸烟者抽烟完成,并将烟草和胶水用完\n", sm->num);
			break;
		}
		else {
			printf("%d号吸烟者没有得到资源,不能吸烟...\n", sm->num);
			break;
		}
	case 3:
		if (sm->sign == 1) {
			printf("%d号吸烟者得到资源开始吸烟...\n", sm->num);
			s->finish = 1;
			s->offer3 = 0;
			sm->sign = 0;
			printf("%d号吸烟者抽烟完成,并将胶水和纸用完\n", sm->num);
			break;
		}
		else {
			printf("%d号吸烟者没有得到资源,不能吸烟...\n", sm->num);
			break;
		}
	}
	return 0;
}
int provide(semaphore* s) {
	int a = rand() % 3 + 1;
	printf("%d\n", a);
	if (s->finish == 1) {
		switch (a) {
		case 1:
			s->offer1 = 1;
			break;
		case 2:
			s->offer2 = 1;
			break;
		case 3:
			s->offer3 = 1;
			break;
		}
	}
	else {
		printf("进程没有使用完资源,还不能派发新的资源...\n");
	}
	return 0;
}
int main()
{
	semaphore s;
	s.finish = 1;
	s.offer1 = 0;
	s.offer2 = 0;
	s.offer3 = 0;
	Smoker s1, s2, s3;
	s1.num = 1, s2.num = 2, s3.num = 3;
	s1.sign = 0, s2.sign = 0, s3.sign = 0;
	//随机生成10个材料供他人选择
	for (int i = 0; i < 10; ++i) {
		provide(&s);
		wait(&s, &s1);
		wait(&s, &s2);
		wait(&s, &s3);
		//printf("抽烟者%2d%2d%2d\n",s1.sign,s2.sign,s3.sign);
		signal(&s, &s1);
		signal(&s, &s2);
		signal(&s, &s3);
		//printf("%2d%2d%2d%2d",s.finish,s.offer1,s.offer2,s.offer3);
	}
	return 0;
}