Linux信号控制——父子进程模拟乘客乘车问题(附源码)

一、问题描述

使用信号的知识,通过信号控制模拟乘客乘车,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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值