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

(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$

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
汽车司机售票员之间必须协同工作,一方面,只有售票员把车门关好了司机才能开车,因此,售票员关好车门应通知司机开车。另一方面,只有当司机已经停 下,售票员才能开门上下客,故司机停车后应通知售票员。假定某辆公共汽车上有两名售票员与一名司机,汽车当前正在始发站停车上客,试设必要的信号灯及赋初值,写出他们的同步过程 分析: 司机停车,通知售票员开门,售票员关门,通知司机开车 使用到的函数和信号量 HANDLE mutex; HANDLE empty; HANDLE full; 创建信号量 HANDLE CreateSemaphore( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,// lpSemaphoreAttributes是信号量的安全属性 可为NULL __in LONG lInitialCount,// lInitialCount是初始化的信号量 __in LONG lMaximumCount,// lMaximumCount是允许信号量增加到最大值 __in_opt LPCWSTR lpName//lpName是信号量的名称 可为NULL ); 创建互斥信号量 HANDLE CreateMutex(  LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针 可为NULL  BOOL bInitialOwner, // 初始化互斥对象的所有者  LPCTSTR lpName // 指向互斥对象名的指针 ); 申请一个资源 WaitForSingleObject(HANDLE full,INFINITE); 释放资源 ReleaseSemaphore( __in HANDLE hSemaphore,// hSemaphore是要增加的信号量句柄 __in LONG lReleaseCount,// lReleaseCount是增加的计数。 __out_opt LPLONG lpPreviousCount//lpPreviousCount是增加前的数值返回。 ); 释放互斥信号量 BOOL ReleaseMutex(HANDLE hMutex); DWORD WaitForMultipleObjects( DWORD nCount, // number of handles in array CONST HANDLE *lpHandles, // object-handle array BOOL bWaitAll, // wait option DWORD dwMilliseconds // time-out interval );
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值