linux中的信号1——进程如何处理信号?

本文介绍了信号处理机制的基础概念,包括信号的来源、处理方式及常见信号类型。详细讲解了signal函数和sigaction函数的使用方法及其区别,为读者提供了丰富的代码示例。

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

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

一、信号概述

1、信号是内容受限的一种异步通信机制

(1)信号的目的:用来进程间通信(IPC)、进程和内核间的通信。

(2)信号是异步的(类似于软件中断,对比硬件中断,如按键,不知道什么时候按下)。

(3)信号本质上是 int 型的数字编号,每个编号有特定的含义,内容是十分有限的。

2、信号由谁发出

(1)用户在终端按下按键。

(2)硬件异常后由操作系统内核发出信号(比如,除以0,导致程序出错)。

(3)用户使用kill命令向其他进程发出信号。

(4)某种软件条件满足后也会发出信号。比如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时也会产生SIGPIPE信号。

3、进程如何处理信号

(1)忽略信号。

(2)捕获信号。信号绑定一个信号处理函数,捕获信号后执行该处理函数。

(3)默认处理。当前进程没有明显地管理这个信号,默认忽略或终止进程。

4、常见信号介绍

(1)信号在内核/usr/include/i386-linux-gnu/bits中定义,信号的编号一般从1开始。

(2)其中 SIGKILL 是无法忽略、无法拦截的,但必须有权限。

(3)其中 SIGCHILD 是wait阻塞时期待得到的信号。

二、与信号处理有关的API

1、signal函数

函数模型

#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函数作用

signal函数绑定一个捕获函数后,信号发生后会自动执行绑定的捕获函数,并且把信号编号作为传参传给捕获函数。signal函数的返回值,在函数出错时为SIG_ERR,没有出错则返回信号之前绑定的旧的处理函数。

如何理解呢?看下面的代码。

#include <stdio.h>
#include <signal.h>
 
static void SignalHandler1(int signo)
{
    printf("\nhaha\n");
}
static void SignalHandler2(int signo)
{
    printf("\nhehe\n");
}
int main()
{
    void (*func)(int);
    if ((func = signal(SIGINT, SignalHandler1)) == SIG_ERR)
    {
        perror("signal\n");
    }
 
    sleep(10);
 
 
    if ((func = signal(SIGINT, SignalHandler2)) == SIG_ERR) 
        //func 赋值为 signal函数的返回值
    {
        perror("signal");
    }
    sleep(10);
    func(2);//注意这里具体是哪个函数。
 
    return 0;
}

运行结果

^C//第一次触发signal
haha//信号处理程序是SignalHandler1,此时signal的返回值是
     //以前的处理signo的函数指针,应该是系统默认的
^C//第二次触发signal
hehe//信号处理程序是SignalHandler2,此时signal的返回值是
     //以前的处理signo的函数指针,应该是SignalHandler1
 
haha//所以此处输出的是SignalHandler1的结果

参数说明

(1)signum为信号编号。

(2)handler为信号所绑定的处理方式,它可能为SIG_IGN、SIG_DFL或者函数。分别表示忽略处理、默认处理、执行该函数。

补充说明

(1)signal函数非常简单好用,捕获信号常用。

(2)绑定处理函数的这种方式,使用signal时,不同版本可能不同。

(3)无法直接地得知之前设置的对信号的处理方法。

代码示例

/*
举例:用signal函数处理SIGINT信号(此信号由ctrl+c时发出)
信号出现时,进程对信号的三种处理方式
(1)默认处理
(2)忽略处理
(3)捕获处理
*/


#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
 
typedef void (*sighandler_t)(int);
 
 
void func(int sig)
{
	if (SIGINT != sig)
		return;
	
	printf("func for signal: %d.\n", sig);
}
 
 
int main(void)
{
	sighandler_t ret = (sighandler_t)-2;
	//signal(SIGINT, func);                 // 指定信号SIGINT为绑定处理函数
	//signal(SIGINT, SIG_DFL);		// 指定信号SIGINT为默认处理
	ret = signal(SIGINT, SIG_IGN);		// 指定信号SIGINT为忽略处理
	if (SIG_ERR == ret)
	{
		perror("signal:");
		exit(-1);
	}
	
	printf("before while(1)\n");
	while(1);
	printf("after while(1)\n");
	
	return 0;
}

2、sigaction函数

函数模型

 补充说明

(1)sigaction比signal更具有可移植性。

sigaction可以单独设置新的捕获,或者单独只获取旧的捕获函数(将新的传参为NULL)。

而signal函数不能单独获取旧的捕获函数,必须设置新的捕获函数,传参后函数返回才获取旧的捕获函数。

(2)用法关键是2个sigaction指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天糊土

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值