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