【IPC 通信】信号处理接口 Signal API(2)

news/2024/5/19 1:34:38 标签: signal, linux, SIGKILL, SIGINT, 计算机网络

         收发信号思想是 Linux 程序设计特性之一,一个信号可以认为是一种软中断,通过用来向进程通知异步事件。

        本文讲述的 信号处理内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解信号编程。


signal

遵循 C11,POSIX.1 - 2008

1.库

标准 c 库,libc, -lc

2.头文件

<signal.h>

3.接口定义

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

4.接口描述

       注意:signal() 的行为会根据不同的 UNIX 版本而变化,同样它也会根据 Linux 版本的不同而不同。考虑到程序的可移植性,尽量避免 signal() 的使用,而是使用 sigacton(2) 代替,可以参考下面移植性部分。

        signal() 设置 signum 信号的处理函数为 handler,处理函数可以是SIG_IGN、SIG_DFL,也可以是程序设计人员定义的函数地址。

        如果 signum 被分发给到一个进程,那么会发生以下行为:

  • 如果处理函数设置成了 SIG_IGN,那么信号会被忽略。
  • 如果处理函数设置成了 SIG_DFL,那么信号的默认关联行为会发生(可以参考 signal(7))。
  • 如果处理函数设置成了一个函数,那么首先会将默认处理函数复位为 SIG_DFL,或者信号被阻塞(参考下面可移植性部分),然后会调用 handler 函数并传递 signum 参数。如果处理函数调用导致了该信号处理阻塞,那么在处理函数返回后,该信号会重新被 unblock。

        SIGKILL 和 SIGSTOP 两个信号不能被捕捉或者忽略。

5.返回值

        signal() 返回信号之前 的处理函数值。发生错误时,signal() 会返回 SIG_ERR,并设置 errno 来提示具体错误。

        错误值定义如下:

EINVALsignum 参数不合法

6.版本

       sighandler_t 是一个 GNU 扩展,它会在 _GNU_SOURCE 定义时暴漏出来。如果定义了_BSD_SOURCE(glibc 2.19 或低版本) 或者 _DEFAULT_SOURCE(glibc 2.19 或高版本),glibc 也定义了 sig_t。不使用这些定义的情况下,signal() 的声明就会有些晦涩:

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

可移植性 

        signal() 只有在将 handler 设置为 SIG_DFL/SIG_IGN 时,才具有移植性。使用 signal() 建立信号处理函数的语义随着系统的不同而不同,POSIX.1 明确允许这些不同的行为。所以不要使用它于此目的。

        POSIX.1 通过 sigaction(2) 接口解决了这种移植上的混乱,sigaction(2)  提供了信号处理调用的明确语义定义。所以,使用 sigaction(2) 来代替 signal()。

7.历史

        C89,POSIX.1-2001

        在原来的 UNIX 系统中,当使用 signal() 建立的信号处理函数被调用时,信号的处理会被设置成 SIG_DFT,并且系统不会阻塞该信号通往其他进程的发布。这相当于调用了 sigaction(2),附带以下标记:

           sa.sa_flags = SA_RESETHAND | SA_NODEFER;

         System V 已提供了 signal() 的语义,不过这个定义有点差劲,因为在处理函数重新建立连接前,可能会连续收到两个信号。更严重的,同一个信号的频繁分发会导致处理函数的递归调用。

        BSD 对此进行了改善,但不幸的是这种改善却改变了现存 signal() 接口的语义。在 BSD 系统上,当一个处理函数调用时,信号处置并没有被重新设置,后面发生的该信号的实例因该处理函数正在执行无法进行分发。更严重的,一些阻塞系统调用会在信号处理函数打断后自动重启。BSD 语义相当于使用下面标记调用 sigaction(2):

           sa.sa_flags = SA_RESTART;

         Linux 上的情景如下:

  • 内核的 signal() 系统调用提供了 System V 语义
  • 默认情况下,glibc 2 及更高版本的 signal() 封装并没有调用内核系统调用,而是调用了 sigaction(2),提供 BSD 语义的标记。只要提供合适的宏定义,就可以提供以上默认行为:glibc 2.19 或低版本的 _BSD_SOURCE 或者 2.19 或更高版本的 _DEFAULT_SOURCE。(默认情况下,这些宏是定义了的,参考 feature_test_macros(7) )。如果这些测试宏没有开启,那么 signal) 提供的是 System V 语义。 

 8.注意

        signal() 在进程的多线程场景下的副作用是未定义的。

        根据 POSIX 定义,进程忽略非 kill(2)/raise(3) 产生的 SIGFPE/SIGILL/SIGSEGV 信号后的行为是未定义的。整数除以 0 是未定义的结果,在一些架构上它会产生 SIGFPE 信号(同样使用 -1 除最大负整数也可能产生 SIGFPE。)忽略这些信号可能会导致无限循环。

        参考 sigaction(2) 获取更多关于将 SIGCHLD 信号的处置设置为 SIGIGN 的信息。

        参考 signal-safety(7) 来查看一些可以在信号处理函数内部调用的异步信号安全的函数。

9.代码

        下面是一个捕捉 CTRL + C 信号的程序。

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

void sighandler(int);

int main()
{
   signal(SIGINT, sighandler);

   while(1) 
   {
      printf("开始休眠一秒钟...\n");
      sleep(1);
   }

   return(0);
}

void sighandler(int signum)
{
   printf("捕获信号 %d,跳出...\n", signum);
   exit(1);
}

下一篇 【计算机网络】信号处理接口 Signal API(2)


http://www.niftyadmin.cn/n/5047230.html

相关文章

python中if not 用法

not与逻辑判断句if连用&#xff0c;代表not后面的表达式为False的时候&#xff0c;执行冒号后面的语句。比如&#xff1a; a False if not a: # 这里因为a是False&#xff0c;所以not a就是True&#xff0c;就能够输出结果hello。print "hello"a None同理在pyth…

2 C++中的引用

C中的引用 上节说到&#xff0c;变量名实际上是一段连续存储空间的别名。很显然我们可以将其命名为其它名字&#xff0c;就像我们有乳名、小名一样。 C引入了引用的概念。 引用可以看作一个已定义变量的别名引用的语法 type& name variate;普通引用在声明时必须用其它的…

canal简单介绍

简介 https://github.com/alibaba/canal 基于 MySQL 数据库增量日志解析&#xff0c;提供增量数据订阅和消费 原理是使用程序模拟一个mysql的从库&#xff0c;使主库发送同步日志给程序&#xff0c;程序再对数据进行处理&#xff0c;比如同步到其他数据库。 使用 下图是一个…

【软件设计师-从小白到大牛】上午题基础篇:第五章 结构化开发方法

文章目录 前言结构化设计1、基本原则真题链接2、内聚与耦合真题链接3、系统结构/模块结构真题链接用户界面设计的黄金原则&#xff08;补充&#xff09;真题链接数据流图&#xff08;补充&#xff09;真题链接系统文档&#xff08;补充&#xff09;真题链接 前言 ​ 本系列文章…

Python:Django框架的Hello wrold示例

Django是Python的目前很常用的web框架&#xff0c;遵循MVC设计模式。 以下介绍如何安装Django框架&#xff0c;并生成最简单的项目&#xff0c;输出Hello world。(开发工具VScode) 一、安装Django 在VScode终端控制台执行以下指令安装Django python install django 如果要查…

RASP初识

需要了解的东西. 是什么 拦截日志&#xff1a;rasp/logs/alarm/alarm.log RASP&#xff08;Runtime application self-protection&#xff09;运行时应用自我保护。 官方英译应用程序不应将大部分运行时保护委托给外部设备。应用程序应该能够自我保护&#xff08;即&#xf…

深度强化学习(一)常识性普及

文章目录 机器学习、强化学习、深度学习的侧重点强化学习的简介强化学习的主要特征强化学习和机器学习的关系强化学习的发展历史 深度强化学习 一些参考的资料&#xff1a; 蘑菇书&#xff1a;https://datawhalechina.github.io/easy-rl/#/chapter1/chapter1 源代码&#xff1a…

idea默认带的equals和hashcode引起的bug

如果出现失效的问题&#xff0c;可以引用下面方式来实现去重