栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

《深入 C 语言和程序运行原理》15 标准库:信号与操作系统软中断有什么关系?(学习笔记)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

《深入 C 语言和程序运行原理》15 标准库:信号与操作系统软中断有什么关系?(学习笔记)

仅作为本人学习《深入 C 语言和程序运行原理》的学习笔记,原课程链接:极客时间《深入 C 语言和程序运行原理》——于航

我们都知道除法运算分母不能为 0,如果在程序中用一个数除以 0,程序中常常会出现“除零异常”。

平时我们在运行程序或与操作系统、底层硬件进行交互时,你可能会遇到下面这些情况:

  1. 程序运行时访问了非法内存,导致段错误(Segmentation Fault);
  2. 程序卡死时或用户想强制关闭程序时,在控制台终端输入 Ctrl+C;
  3. 计算机底层硬件出现故障,导致无法实现特定功能;
  4. 。。。

以上这些情况都可以通过“信号”来解决。

什么是信号

软中断信号(signal,简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。

——百度百科

信号产生是一个随机的过程。程序不需要轮询某个全局变量来处理事情,而是可以提前设定好当某个信号到来时如何进行处理,这是典型的异步事件处理方式。

信号与软件中断

信号是一种软中断。

通常来说,中断触发分为两种形式,即硬件中断和软件中断,其中硬件中断是指与计算机硬件特定状态相关的中断过程,该过程直接由硬件触发。

软件中断是指由计算机软件,通过机器指令引起的 CPU 执行流程的临时转移过程,系统调用也是一种软中断。

在 C 代码中与信号交互

C 语言自 C90 标准开始,便提供了 signal.h 头文件,下面这份代码出自原文:

#include 
#include 
#include 
void sigHandler(int sig) {
  printf("Signal %d catched!n", sig);
  exit(sig);
}
int main(void) {
  signal(SIGFPE, sigHandler);
  int x = 10;
  int y = 0;
  printf("%d", x / y);
}

main 函数开头先用 signal()函数设置了一个信号捕获,当 SIGFPE 信号触发时,便会调用 sigHandler() 函数。


Signal 8 对应的就是 SIGFPE 信号,下面是 C 标准库提供的 6 种不同类型的信号:

图片来源:课程原文

除了上面自定义信号处理函数的方式外,C 标准库还为我们提供了两种基本的信号处理方式,分别是 SIG_DEF(使用默认的信号处理函数)和 SIG_IGN(忽略该信号),它们可以直接作为 signal() 函数的第二个参数使用。

但是并非所有类型的信号都可以忽略,有些难以恢复软硬件异常对应的信号不能被忽略,比如 SIGTERM,或者 Linux 上的 SIGKILL 和 SIGSTOP 等。

可重入函数

信号处理可以发生在程序运行的任意时刻,但是有些时候,程序运行到一个函数 A 内部,此时来了一个信号,导致 CPU 转去执行信号处理函数,但信号处理函数内部也有函数 A,这样会不会有影响呢?

答案是如果函数 A 是不可重入函数,上面这种情况就会导致意想不到的后果,很多 C 标准库函数,如 printf、exit、malloc 都是不可重入函数。这也就是我们常说的中断内不能放不可重入函数。

C 标准库为我们提供了一个名为 sig_atomic_t 的整数类型,即使中断可能打断执行流程,对该类型变量的读写也都是原子的,这是一种在异步信号处理场景下的原子性。

在处理信号(signal)的时候,有时对于一些变量的访问希望不会被中断,无论是硬件中断还是软件中断,这就要求访问或改变这些变量需要在计算机的一条指令内完成。通常情况下,int类型的变量通常是原子访问的,也可以认为 sig_atomic_t就是int类型的数据,因为对这些变量要求一条指令完成,所以sig_atomic_t不可能是结构体,只会是数字类型。

——百度百科

这里我不是很理解,反正无论如何,中断函数最好不要使用不可重入函数。

多线程应用的信号处理

C 语言并没有对并发编程中的信号处理做任何约束和建议,所以在不同操作系统上使用 signal() 和 raise() 函数,可能功能上会有差异。

所以如果要考虑程序的移植性,最好不要在多线程应用中使用信号处理。处理方法:可以通过宏判断来区分不同的操作系统,从而在不同系统上运行不同的代码。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/836437.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号