信号练习: (通过信号模拟 司机--售票员 )

(1)要求:

    1.平常司机在车上休息,售票员在观察上车人数。
    2.售票员发现车上人满了就提醒司机发车。
    3.中途停两个站: 9km. 15km处, 这时售票员要提醒司机。
    6.总里程20公里。
    7.到终点站后司机提醒售票员让所有乘客下车。
    8.售票员退出后, 司机才能退出。

(2)练习源码

// driver-conductor.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define CUR printf("Cur in: %s %d\n", __FILE__, __LINE__)
#define ERR printf("Err in: %s %d\n", __FILE__, __LINE__)

#define SIG_START 	 SIGRTMIN+1	// 发车信号
#define SIG_END   	 SIGRTMIN+2	// 终点站信号
#define SIG_STATION  SIGRTMIN+3	// 途径站信号

#define SHM_SIZE 1024
#define SHM_KEY 0x123

#define LENGTH 20
// 需要共享内存: 父子进程都要使用这个变量(常规变量fork后在父子进程中各有一份, 但值不同步)
int *mileage = NULL;

/* 信号处理函数  */
void sig_start(int sig)			// 司机进程接收这个信号
{	printf("driver: start journey\n");
}
void sig_station(int sig)		// 司机进程接收这个信号
{	
	printf("driver: in %d station\n", *mileage);
}
void sig_end(int sig)			// 售票员进程接收这个信号
{	
	printf("conductor: all put off\n");							// 售票员下车,退出进程
	printf("conductor: out\n");
	exit(0);
}
int running (void)	// 在司机进程
{	while(1)
	{	printf("cur  %d km\n", *mileage);	// 司机的mileage
		sleep(1);
		*mileage += 1;
		if(*mileage > LENGTH)
			goto r;
	}
r:
	printf("driver: end station\n");
	return 0;
}

int car_full(void)
{	char buf[20];
	while(1)
	{	bzero(buf, 20);
		printf("if car full, please input full\n");
		fgets(buf, 20, stdin);
		if (!strncmp("full", buf, 4))
			return 1;
	}
}
int in_station()			// 停经站
{	if ((*mileage == 9) || (*mileage == 15))
		return 1;
	return 0;
}

int main(int argc, char **argv)	// 为了简化代码, 将不判断返回值
{
	int ret;
	int drvpid, conpid;		// 司机,售票员pid
	int shmid;
	char *addr;				// 共享内存地址

	// 创建共享内存
	shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0777);	
	if (shmid < 0)
	{	shmid = shmget(SHM_KEY, SHM_SIZE, 0777);
		if (shmid < 0)
			ERR;
	}
	// 映射共享内存到主进程虚拟地址空间
	addr = shmat(shmid, NULL, 0);
	bzero(addr, SHM_SIZE);
	mileage    = (int *)addr;
	*mileage   = 0;	// 总里程30km
	
	drvpid = getpid();		// 父子进程得到的值一样
	ret = fork();			// 父子进程: start=0, stop=0
	if(ret < 0)
		ERR;
	else if (!ret)			// 售票员
	{	shmid = shmget(SHM_KEY, SHM_SIZE, 0777);
			if (shmid < 0)
				ERR;
		if(SIG_ERR == signal(SIG_END, sig_end))	 // 安装终点信号	
			ERR;	
	
		// 映射共享内存到子进程虚拟地址空间
		addr = shmat(shmid, NULL, 0);	
		if(car_full())
			kill(drvpid, SIG_START);
		while(1)
		{	if (in_station())
				kill(drvpid, SIG_STATION);
			usleep(2000);
			
			// 如果收到终点站信号, 售票员要求所有乘客下车, 然后自己退出
		}
		exit(0);
	}
	
	//司机
	if(SIG_ERR == signal(SIG_START,  sig_start))		// 司机安装发车信号		
		ERR;	
	if(SIG_ERR == signal(SIG_STATION,  sig_station))	// 司机安装途径站信号		
		ERR;	
	
	conpid = ret;				// 售票员PID
	printf("conpid = %d\n", conpid);
	printf("driver: rest\n");
	pause();					// 等待售票员"发车信号"到来
	running();					// 汽车正常行驶过程中, 可能被售票员发送的信号打断
	kill(conpid, SIG_END);		// 通知售票员让所有乘客下车
	ret = wait(NULL);					// 等待售票员退出, 自己才能关车
	printf("ret = %d\n", ret);
	printf("driver out\n");
	return 0;
}


(3)执行结果

book@gui_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$ ./a.out
conpid = 9821
driver: rest
if car full, please input full
full                    // 键入"full 回车"
driver: start journey
cur  0 km
cur  1 km
cur  2 km
cur  3 km
cur  4 km
cur  5 km
cur  6 km
cur  7 km
cur  8 km
cur  9 km
driver: in 9 station
cur  10 km
cur  11 km
cur  12 km
cur  13 km
cur  14 km
cur  15 km
driver: in 15 station
cur  16 km
cur  17 km
cur  18 km
cur  19 km
cur  20 km
driver: end station
conductor: all put off
conductor: out
ret = 9821
driver out
book@gui_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$

猜你喜欢

转载自blog.csdn.net/qq_38813056/article/details/85223938