About signal in linux environment

本文深入探讨Unix及类Unix系统中的信号处理机制,包括信号的概念、类型及其在进程间的通信作用。详细介绍了signal函数的定义与应用,如何使用raise和kill函数生成信号,以及信号在父子进程中的使用案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 信号概念

在计算机科学中,信号(英语:Signals)是 Unix、类 Unix 以及其他 POSIX 兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。当一个信号发送给一个进程,操作系统中断了进程 正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。
每个信号都有一个名字, 这些名字都以三个字符 SIG 开头。 例如,SIGABRT 是夭折信号, 当进程调用abort 函数时产生这种信号。SIGALRM 是闹钟信号,当由 alarm 函数设置的计时器超时后产生此信号。在UNIX 系统中,这些信号都定义在头文件 <signal.h> 中,并且都是以一个正整数来表示(信号编号)。通过在shell 中运行命令 kill -l 可以查看当前系统所执行的所有信号。
UNIX 系统规定了内核可以对信号执行以下三种处理行为,

  1. 忽略此信号。有两个信号 SIGKILL 和 SIGSTOP 不可忽略,这两个信号提供给超级用户终止或停止
    进程的可靠方法。
  2. 执行系统默认动作。大多数信号的默认动作是终止进程。
  3. 捕获信号,执行用户自定义的处理函数。
二 信号处理
2.1 signal 定义
       #include <signal.h>
       
       void (*signal(int num, void (*handler)(int))) (int)

       typedef void (*sighandler_t)(int);
       sighandler_t signal(int signum, sighandler_t handler);
2.2 signal的简单应用:
#include <signal.h>
#include <stdio.h>

/*
*	void (*signal(int num, void (*handler)(int))) (int)
*	typedef void(handler_t)(int)
*	handler_t signal(int, handler_t)
*/

void handler(int num)
{
	printf("handler: num = %d\n", num);
}

int main(int argc, char const *argv[])
{
	//capture signal and binding signal handle function
	signal(SIGINT, handler);
	while (1);
	return 0;
}

Ubuntu下测试输出:

xxx@ubuntu:~/Documents/linux环境高级编程/signal$ ./a.out 
^Chandler: num = 2
^Chandler: num = 2
^Chandler: num = 2
^\退出
2.3 raise and kill

UNIX 系统提供了两个函数 kill 和 raise 来产生信号。kill 函数将信号发送给指定的进程或进程组。
raise 函数则允许进程向自身发送信号。
#include <signal.h>

int kill(pid_t pid, int signo);
pid : 需要发送信号的进程的进程号
signo : 信号值

int raise(int signo); 给自己发送信号 等价于 kill(getpid(),signo);

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int num)
{
	printf("raise a signal!\n");
}


int main(int argc, char const *argv[])
{
	//ignore SIGINT	 signal
	//signal(SIGINT, SIG_IGN);
	//default
	//signal(SIGINT,SIG_DFL);
	
	signal(SIGINT, handler);
	sleep (3);
	raise(SIGINT);    //3秒后给自己发送一个SIGINT信号 Default action is to terminate the process. 终止进程

	return 0;
}

Ubuntu下测试输出:

xxx@ubuntu:~/Documents/linux环境高级编程/signal$ ./a.out 
raise a signal!   //等待三秒之后的输出
2.4 signal在父子进程中使用

signal提供关于用于自定义的信号值如下:
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
关于signal更多信息使用 man 7 signal 命令查看

使用signal在父子进程中使用代码如下所示:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

//wait : will chock and always ask. 
//SIGHOLD: is similar to interrupt.

void my_handler(int num)
{
	printf("the subprocess has ended!%d\n",num);
	printf("ID- %d, this is my_handler : num = %d\n", getpid(),num);
	int status;
	pid_t pid = wait(&status);
	// xxxxxx  See (man wait) for further specification for the status resolution
}

void my_siguser1(int num)
{
	printf("ID- %d, this is my_siguser1 : num = %d\n", getpid(),num);
}

int main(int argc, char const *argv[])
{
	pid_t pid = fork();

	if (pid < 0){
		perror("fork");
		return 0;
	}if (pid > 0){  // parent process
		printf("parent process : pid = %d, ppid = %d\n", getpid(), getppid());

		sleep(1);
		signal(SIGCHLD,my_handler); 
		kill(pid, SIGUSR1);
		while(1);

	}if (0 == pid){  //subprocess
		printf("subprocess : pif = %d, ppid = %d\n", getpid(),getppid());
		
		//Both SIGUSR1 and SIGUSR2 are for user define
		signal(SIGUSR1, my_siguser1);   //make SIGUSR1 bind my_siguser1 fuction

		sleep(3);
		
		printf("the subprocess will end\n");
		//SIGCHLD before the subprocess end, it will send a SIGCHLD signal to parent process

	}
	return 0;
}

Ubuntu下测试输出:

xxx@ubuntu:~/Documents/linux环境高级编程/signal$ ./a.out 
father process : pid = 3395, ppid = 2845
subprocess : pif = 3396, ppid = 3395
ID- 3396, this is my_siguser1 : num = 10
the subprocess end
the subprocess has ended!17
ID- 3395, this is my_handler : num = 17
^C

2.5 signal在父子进程中应用

使用fork创建两个子进程,父进接收stdin的输入,如果输入中含有“terminate_all”,则终止所有进程(包括父进程),否则,如果输入中含有“terminate_01”,则终止第一个子进程,否则,如果输入中含有“terminate_02”,则终止第二个子进程。
具体代码实现如下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>


int main(int argc, char const *argv[])
{
	pid_t pid1 = fork();
	if (pid1 < 0){
		perror("fork1");
		return -1;
	}else if (pid1 > 0){ 
		pid_t pid2 = fork();
		if (pid2 < 0){
			perror("fork2");
			return -1;
		}else if (pid2 > 0){ //parent process
			char * ch = (char *)malloc(100);
			while (1){
				scanf("%s", ch);
				if (strstr(ch, "terminate_all")){
					kill(pid1,SIGINT);
					kill(pid2,SIGINT);
					raise(SIGINT);
				}else if (strstr(ch, "terminate_01")){
					kill(pid1,SIGINT);
				}else if(strstr(ch, "terminate_02")){
					kill(pid2,SIGINT);
				}
			}
						
		}else if(0 == pid2){ // subprocess2 
			while (1)
			{
				sleep(5);
				printf ("this is subprocess2\n");
			}
		}

	}else if(0 == pid1){ // subprocess1 
		while (1)
			{
				sleep(5);
				printf ("this is subprocess1\n");
			}
	}
	return 0;
}

Ubuntu下测试输出:

xxx@ubuntu:~/Documents/linux环境高级编程/signal$ ./a.out 
this is subprocess2
this is subprocess1
terminate_01
this is subprocess2
this is subprocess2
terminate_02
terminate_all

xxx@ubuntu:~/Documents/linux环境高级编程/signal$ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值