一、问题描述
使用信号的知识,通过信号控制模拟乘客乘车,SIGINT已上车、SIGQUIT中途下车、SIGTSTP到终点站
二、用到的知识点
1.fork()函数创建父子进程、回收子进程waitpid()
2.信号发送kill()
3.捕捉信号pause()
4.信号处理signal、sigaction
5.屏蔽信号
6.用到的信号
7.错误输出perror()
8.退出进程exit()
三、知识储备
1.fork()创建父子进程
#include <unistd.h>
pid_t pid;//记录进程号
if((pid=fork())<0)//创建进程,同时通过它的返回值(进程号)判断创建是否成功
//创建成功,返回子进程号
//创建成功后,父子进程理论上说是同时开始运行
{
perror("fork");//输出错误信息
}
if(pid==0)//子进程
{
/*code*/
}
else//父进程,pid=子进程的进程号
{
waitpid()//等待子进程结束并回收
return 0;//退出
}
可以通过getpid()得到当前进程的进程号
可以通过getppid()得到当前进程的父进程号
2.kill()信号发送
#include <sys/types.h>
#include <signal.h> int kill(pid_t pid, int sig);
kill(getppid());
3.pause()信号捕捉
signal(SIGINT,my_func);//信号处理函数
pause();//等待信号,捕获后优先执行signal()等信号处理函数,然后执行默认处理方法
4.信号处理signal、sigaction
#include <signal.h>
typedef void( *sighandler_t)(int);//信号处理的自定义方法
sighandler_t signal(int signum, sighandler_t handler);
void my_func(int sign_no)//信号处理的自定义方法,只能是一个参数(信号),eg.SIGINT
{
printf("I have got %d",sign_no);
}
signal(SIGINT,my_func);//信号处理函数
#include <signal.h>
int sigaction(int signum, const struct sigaction*act,struct sigaction *oldact);
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
struct sigaction action;
sigaction(SIGUSR2,0,&action);
action.sa_handler = driver_func;
sigaction(SIGUSR2,&action,0);
5.屏蔽信号sigprocmask
#include <signal.h>
int sigprocmask(int how, const sigset_t *set,sigset_t *oldset);
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset,SIGINT);//将SIGINT添加到屏蔽信号集中
sigaddset(&sigset,SIGQUIT);
sigprocmask(SIG_BLOCK,&sigset,NULL);
注:这里也可以使用自定义signal函数进行处理:
signal(SIGINT, SIG_IGN);//对该信号采取忽略处理。
6.用到的信号说明
(1)SIGINT:程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
(2)SIGQUIT:和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制。 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。
(3)SIGTSTP:停止进程的运行, 但该信号可以被处理和忽略。 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号。
(4)SIGUSR1、SIGUSR2:留给用户使用。
7.错误输出perror()
#include <stdio.h> void perror(const char *s);
#include <errno.h> const char *sys_errlist[]; int sys_nerr; int errno;
perror("fork()");
8.退出进程exit()
#include <stdlib.h>
void exit(int status);
四、源代码
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
//getpid()当前进程号
//getppid()当前的进程的父进程号
//父子进程(仅两个进程)之间的进程号相差为1
void conductor_func(int sign_no)
{
if(sign_no==SIGINT)
{
printf("conductor:I have got SIGINT\n");
kill(getpid()+1,SIGUSR1);//conducor为父进程,此处给子进程发送信号(父进程号+1 = 子进程号)
printf("conductor send SIGUSR1 to %d after\n",getpid()+1);
}
else if(sign_no==SIGQUIT)
{
printf("conductor:I have got SIGQUIT\n");
kill(getpid()+1,SIGUSR2);
printf("conductor send SIGUSR2 to %d after\n",getpid()+1);
}
else if(sign_no==SIGUSR1)
{
printf("conductor:I have got SIGUSR1\n");
printf("conductor:get off the bus\n");
}
}
void driver_func(int sign_no)
{
if(sign_no==SIGUSR1)
{
printf("driver:I have got SIGUSR1\n");
printf("driver:let's go\n");
printf("waiting for signal SIGQUIT(ctrl+\\)\n");
}
else if(sign_no==SIGUSR2)
{
printf("driver:I have got SIGUSR2\n");
printf("driver:stop the bus\n");
}
else if(sign_no==SIGTSTP)
{
printf("driver:I have got SIGTSTP\n");
kill(getppid(),SIGUSR1);
printf("driver send SIGUSR1 to %d after\n",getppid());
}
}
int main(int argc, char const *argv[])
{
pid_t pid;
struct sigaction action;
//创建父子进程
if ((pid=fork())<0)
{
perror("fork");
}
printf("main fork success\n");
//conductor父进程
//driver子进程
//接收(捕获)信号pause()
if(pid==0)//driver子进程
{
/*driver屏蔽信号SIGINT、SIGQUIT*/
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset,SIGINT);
sigaddset(&sigset,SIGQUIT);
sigprocmask(SIG_BLOCK,&sigset,NULL);
printf("driver my pid is %d\n",getpid() );
sigaction(SIGUSR1,0,&action);
action.sa_handler = driver_func;
sigaction(SIGUSR1,&action,0);
pause();
sigaction(SIGUSR2,0,&action);
action.sa_handler = driver_func;
sigaction(SIGUSR2,&action,0);
pause();
sigaction(SIGTSTP,0,&action);
action.sa_handler = driver_func;
sigaction(SIGTSTP,&action,0);
printf("waiting for signal SIGTSTP(ctrl+z)\n");
pause();
printf("driver process is end\n");
}
else//conductor父进程
{
/*conductor 屏蔽信号SIGTSTP*/
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset,SIGTSTP);
sigprocmask(SIG_BLOCK,&sigset,NULL);
sleep(1);//给时间与子进程先完成信号屏蔽操作
printf("conductor my pid is %d\n",getpid() );
printf("this id driver's pid is %d\n",pid );
/*sigaction结构初始化*/
sigaction(SIGINT,0,&action);
action.sa_handler = conductor_func;
sigaction(SIGINT,&action,0);
printf("waiting for signal SIGINT(ctrl+c)\n");
pause();
sigaction(SIGQUIT,0,&action);
action.sa_handler = conductor_func;
sigaction(SIGQUIT,&action,0);
pause();
sigaction(SIGUSR1,0,&action);
action.sa_handler = conductor_func;
sigaction(SIGUSR1,&action,0);
pause();
//等待子进程结束
waitpid();
exit(0);
}
五、源代码附件
链接:https://pan.baidu.com/s/1iLl0dXT1iBmCEe9qPHimZA
提取码:ryj6