信号代码样例

父进程管理两个子进程,实现功能如下
1. 父进程被kill之后,子进程也会被kill
2. 子进程被kill之后,子进程会被父进程重新拉起
3. 此进程为守护进程

编译后运行编译出来的文件,发现已经是守护进程了
执行ps -ef| grep maggie命令,会发现有三个同名进程,一个父进程,两个子进程
kill子进程,父进程会将其重新拉起
kill父进程,父进程会将结束,并同时杀死两个子进程
kill父进程时会发现,waitpid函数返回-1


#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <map>
#include <string>
using std::map;
using std::string;
volatile int sigFlag;

void SignalHandler(int sig)
{
	printf("SignalHandler, sig:%d, pid: %d\n", sig, getpid());
	sigFlag = 1;
}

void SetSignal()
{
	struct sigaction sa;
	memset(&sa, 0, sizeof(sa));
	//void (*sa_handler)(int), 信号处理函数
	//sigset_t sa_mask, 用来设置信号屏蔽集,当信号函数返回后,还原
	//int sa_flags, 指定对信号处理的各个选项
	//void (*sa_signation)(int, siginfo_t *, void *), 是一个替代的信号处理程序,当sa_flag为SA_SIGINFO时,使用该处理程序。比sa_handler带有更多的参数
	sa.sa_handler = SignalHandler;
	
	//sigaction函数
	//1. 第一个参数,捕捉的信号
	//2. 第二个参数,相应信息
	//3. 第三个参数, 如果为非空,会返回该信号的上一个动作
	//设置主进程如果被中断了,如何处理函数
	//
	//SIGINT: 用户按中断键(一般采用Delete或者Ctril+C),终端驱动程序产生此信号,发送给前台进程组中的每个进程
	sigaction(SIGINT, &sa, NULL);
	//SIGHUP: 与终端链接断开
	sigaction(SIGHUP, &sa, NULL);
	//SIGTERM:由kill(1)命令发送的系统默认终止信号
	sigaction(SIGTERM, &sa, NULL);
	//SIGQUIT: 当用户在终端按退出键(一般采用Ctrl+\),此信号不止终止钱袋进程组,同时产生一个core文件
	sigaction(SIGQUIT, &sa, NULL);

	//signal(SIGPIPE, SIG_IGN)  
    //当服务器close一个连接时,若client端接着发数据。
    //根据TCP 协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。 
    //根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。
    //若不想客户端退出可以把SIGPIPE设为SIG_IGN 
    signal(SIGPIPE,SIG_IGN);

	//取消以下信号的屏蔽
    sigset_t sset;
    sigemptyset(&sset);
    sigaddset(&sset, SIGBUS);
    sigaddset(&sset, SIGILL);
    sigaddset(&sset, SIGFPE);
    sigaddset(&sset, SIGSEGV);
    sigaddset(&sset, SIGCHLD);//设置child中断时产生的信号不会被阻塞
    sigaddset(&sset, SIGABRT);
    //设置信号屏蔽
    //1. 第一个参数, SIG_BLOCK是或操作,表示新增需要被屏蔽的信号
    //SIG_UNBLOCK是取消以下信号的阻塞
    //SIG_SETMASK是赋值操作,设置需要屏蔽的信号,并与原先无关
    //2. 第二个参数,需要修改的信号
    //3. 第三个参数,如果不是空,获得操作后的信号屏蔽信息
    sigprocmask(SIG_UNBLOCK, &sset, &sset);
}

void init()
{
	sigFlag = 0;
	//设置信号
	SetSignal();

	//设置守护进程
	//1.第一个参数:为0时,将根目录修改为工作目录 
	//2.第二个参数:为0时,做输入,输出以及错误输出重定向到/dev/null 
	daemon(1, 1);
}

pid_t ForkChild(int channel)
{
	pid_t p = fork();
	if(p < 0) {
		return -1;
	}

	if(p != 0){ //parent
		return p;
	}

	printf("creat child[%d]\n", channel);
	//child
	while(!sigFlag){
		printf("child[%d]\n", channel);
		sleep(3);
	}
	printf("-----------child[%d]_end------------\n", channel);
	//必须是exit不能是return,否则会继续进行
	exit(10);
}

int main()
{
	//初始化
	init();

	map<pid_t, int> list;
	map<pid_t, int>::iterator iter;
	//生成两个子进程
	for(int i = 0; i < 2; i++){
		pid_t p = ForkChild(i);
		list[p] = i;
	}

	while(!sigFlag){
		int status = 0;
		//watipid函数用来等待父进程接收到子进程的SIGCHLD信号
		//1. 第一个参数,pid_t pid
		//pid == -1: 等待任一子进程,此种情况下与wait函数相等
		//pid > 0: 等待进程ID与pid相等的子进程
		//pid == 0:等待组ID等于调用进程组ID的任一子进程
		//pid < -1:等待组ID等于pid绝对值的任一子进程
		//2. 第二个参数,int *statloc,存放终止进程的终止状态
		//3. 第三个参数 int option, 进一步控制waitpid操作,可支持作业控制,以及设置wait的非阻塞版本,<<Uinix环境高级编程>>P193
		//4. 成功返回进程id,失败返回0
		printf("--------waitpid----------\n");
		pid_t p = waitpid(-1, &status, 0);//此处waitpid相当于wait函数
		if(p == 0) {
			continue;
		}
		printf("--------pid:%d----------\n", p);
		iter = list.find(p);
		if(iter == list.end()){
			printf("GET error pid!");
			break;
		}
		//重新拉起子进程
		int channel = iter->second;
		list.erase(iter);
		p = ForkChild(channel);
		list[p] = channel;
	}

	printf("-----sigFlag:%d-------------\n",sigFlag);

	//父进程被kill之后,杀死两个子进程
	for(iter = list.begin(); iter != list.end(); iter++) {
		if(iter->first != -1){
			kill(iter->first, SIGTERM);
		}
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值