Linux系统编程(信号处理机制)

2023-07-13 00:30:00


前言

本篇文章我们来讲解信号的处理机制,信号处理在Linux操作系统中必不可少,这一点值得大家注意,信号又会与中断,异常一起讨论,那么下面我们就来看看到底什么是信号吧。

一、中断,异常,信号的区别

中断、异常和信号是计算机系统中的三个相关但不完全相同的概念。它们在发生的时机、触发方式和处理机制上有所不同。

中断(Interrupt):

1.中断是由硬件发出的一种信号,用于打断处理器当前的执行流程,以响应特定的硬件事件或请求。

2.中断可以来自外部设备(例如键盘、鼠标、硬盘控制器)或系统内部(例如定时器、异常或错误)。

3.当发生中断时,处理器会暂停当前的执行并切换到中断处理程序来处理中断事件,然后在处理完中断后回到原来的执行上下文。

异常(Exception):
1.异常是在程序执行期间发生的事件或错误条件,可能导致程序的正常流程中断。

2.异常可以是由硬件错误(例如除零错误、无效的内存访问)或软件错误(例如逻辑错误、非法操作)触发的错误情况。

3.异常通常是同步的,也就是说,它们在执行特定的指令时发生,并由程序自身或相关硬件直接处理。

4.异常的处理方式通常由编程语言、操作系统或硬件定义,可以通过异常处理机制(例如 try-catch 块)捕获和处理。

信号(Signal):

1.信号是一种在软件层面上由操作系统或进程间通信机制发送的异步通知。

2.信号可以用于通知进程发生的特定事件,如用户操作(例如按下 Ctrl+C),操作系统事件(例如进程终止),或由其他进程发送的消息。

3.信号是在进程执行期间以异步方式发出的,可以打断当前的执行流程。

4.信号通常用于处理外部事件或异常情况,例如捕获异常,终止进程或重新启动进程等。

总结:

1.中断是由硬件发出的打断处理器当前执行流程的信号,用于响应硬件事件。

2.异常是在程序执行期间发生的事件或错误条件,用于响应特定的错误情况。

3.信号是在软件层面上由操作系统或进程间通信机制发送的异步通知,用于处理外部事件或异常情况。

它们在触发方式、处理机制和使用场景上有所不同,但都可以用于在计算机系统中处理特定的事件、错误和异常情况。

二、信号在Linux中的标识

每个信号都由一个唯一的数字标识符来表示,这些数字被称为信号编号。

信号编号是整数值,通常用正整数来表示,例如SIGINT、SIGTERM等。这些信号编号定义在系统头文件 <signal.h> 中,并在C语言中使用 SIG 前缀。

以下是一些常见的信号编号及其含义:

SIGHUP (1): 终端挂起或控制进程终止。

SIGINT (2): 使用键盘输入的中断信号。

SIGQUIT (3): 使用键盘输入的退出信号。

SIGILL (4): 非法指令。

SIGABRT (6): 异常终止。

SIGFPE (8): 浮点异常。

SIGKILL (9): 强制进程终止。

SIGALRM (14): 闹钟超时。

SIGTERM (15): 终止请求。

三、信号处理相关函数

signal()

函数原型:

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

功能:signal() 函数用于注册信号处理函数,指定在接收到特定信号时要执行的操作。

参数:

signum:要捕获和处理的信号编号。
handler:指向信号处理函数的指针,可以是自定义函数或内置的信号处理函数。
返回值:返回一个函数指针,指向以前注册的信号处理函数。

raise()

函数原型:

int raise(int sig)

功能:raise() 函数用于在当前进程内部生成信号。它向当前进程发送指定的信号。
参数:

sig:要发送的信号编号。
返回值:成功时返回0,否则返回一个非零值。

kill()

函数原型:

int kill(pid_t pid, int sig)

功能:kill() 函数用于向指定进程或进程组发送信号。

参数:
pid:要发送信号的进程的进程ID(PID)。可以是正整数值,表示单个进程的PID,也可以是负整数值,表示进程组的PID(将信号发送给该进程组中的所有进程)。
sig:要发送的信号编号。
返回值:成功时返回0,否则返回一个非零值。

这些函数可以一起使用来进行信号的处理。首先,使用 signal() 函数注册信号处理函数,指定接收到特定信号时要执行的操作。然后,可以使用 raise() 函数在当前进程中生成信号,或使用 kill() 函数向其他进程发送信号。

需要注意的是,不同的信号有不同的含义和用途。要正确使用信号处理函数和相关函数,需要了解不同的信号及其处理方式。可以通过查阅相关文档或系统头文件 <signal.h> 了解所有可用的信号及其意义。

四、代码实验

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

void signal_handle(int sig)
{
    printf("sig = %d\n", sig);
}

int main(void)
{

    signal(SIGINT, signal_handle);

    while(1)
    {
        sleep(1);
    }

    return 0;
}

执行效果:
在这里插入图片描述
按下ctrl加c后被信号处理函数捕捉到了,并且打印了信号的数值。

下面的代码演示了怎么样使用信号进行线程之间通信。

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

void signal_handle(int sig)
{
    printf("sig = %d\n", sig);
}

int main(void)
{

    signal(40, signal_handle);

    while(1)
    {
        sleep(1);
    }

    return 0;
}
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>

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

    kill(pid, 40);

    raise(SIGINT);

    while(1)
    {
        sleep(1);
    }

    return 0;
}

总结

本篇文章就讲解到这里,大家看完后可以好好实验一下。

更多推荐

第36章_瑞萨MCU零基础入门系列教程之步进电机控制实验

本教程基于韦东山百问网出的DShanMCU-RA6M5开发板进行编写,需要的同学可以在这里获取:https://item.taobao.com/item.htm?id=728461040949配套资料获取:https://renesas-docs.100ask.net瑞萨MCU零基础入门系列教程汇总:https://b

Spring Boot 简介与入门

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

数据结构:树和二叉树之-堆排列 (万字详解)

目录树概念及结构1.1树的概念1.2树的表示​编辑2.二叉树概念及结构2.1概念2.2数据结构中的二叉树:​编辑2.3特殊的二叉树:​编辑2.4二叉树的存储结构2.4.1顺序存储:2.4.2链式存储:二叉树的实现及大小堆排列1功能展示2定义基本结构3初始化4打印5销毁6插入7向上调整8交换两数组元素之间的值9删除10向

Kubernetes(K8S)集群部署

目录一、创建3台虚拟机二、为每台虚拟机安装Docker三、安装kubelet3.1安装要求3.2为每台服务器完成前置设置3.3为每台服务器安装kubelet、kubeadm、kubectl四、使用kubeadm引导集群4.1master服务器4.2node1、node2服务器4.3初始化主节点4.4work节点加入集群

【C语言趣味教程】(1) 深入浅出 HelloWorld:通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解

🔗《C语言趣味教程》👈猛戳订阅!!!💭写在前面:这是一套C语言趣味教学专栏,目前正在火热连载中,欢迎猛戳订阅!本专栏保证篇篇精品,继续保持本人一贯的幽默式写作风格,当然,在有趣的同时也同样会保证文章的质量,旨在能够产出"有趣的干货"!本系列教程不管是零基础还是有基础的读者都可以阅读,可以先看看目录!标题前带星号(

第二证券:什么是a股b股?

在我国的股市中,我们经常会听到“A股”和“B股”这两个名词。那么,终究什么是A股和B股呢?首先,A股全称为“A股票”,是指在我国境内上市的以人民币计价的股票。A股首要面向国内出资者,只要具有必定条件的内地居民和安排出资者才可出资A股。此外,A股还分为两种:人民币A股和港币A股。前者是在我国境内发行的A股,后者则是在香港

Redis 面试题——缓存穿透、缓存击穿和缓存雪崩

目录1.缓存穿透2.缓存击穿3.缓存雪崩4.总结参考文章:缓存实战(1)缓存雪崩、缓存击穿和缓存穿透入门简介及解决方案1.缓存穿透(1)问题描述:缓存穿透是指在高并发场景下,大量的请求访问一个不存在于缓存中也不存在于数据库中的数据,导致每次请求都要查询数据库,增加了数据库的负载。通常发生在恶意攻击、频繁访问不存在的数据

OSCP系列靶场-Esay-Moneybox保姆级

OSCP系列靶场-Esay-Moneybox目录OSCP系列靶场-Esay-Moneybox总结准备工作信息收集-端口扫描目标开放端口收集目标端口对应服务探测信息收集-端口测试21-FTP端口的信息收集21-FTP版本版本信息21-FTP端口匿名登录测试(存在)21-FTP端口-文件GET收集21-FTP端口-PUT上

微服务 第一章 Java线程池技术应用

系列文章目录第一章Java线程池技术应用文章目录系列文章目录@[TOC](文章目录)前言1、Java创建线程方式回顾1.1、继承Thread类(只运行一次)1.1.1、改造成主线程常驻,每秒开启新线程运行1.1.2、匿名内部类1.1.3、缺点1.1.4、扩展知识:Java内部类1.1.4.1、静态内部类1.1.4.2、

机器学习实战:Python基于Ridge岭回归进行正则化(十三)

文章目录1.前言1.1岭回归的介绍1.2岭回归的应用2.自定义数据集实战演示2.1导入函数2.2创建数据集2.3alpha=0、1、10、100的分别情况3.Dushanbe_house数据集实战演示3.1导入函数和数据3.2剔除空值及可视化3.3整理数据3.4训练和测试数据集3.5评估数据集4.讨论1.前言1.1岭回

Python 04 之变量【列表,元组,集合,字典,字符串】

😀前言在Python编程语言中,我们经常会遇到各种数据类型和相应的操作方法。理解和掌握这些基本构造是进行有效编程的前提。在本文中,我们将介绍两种非常重要的数据结构-集合和字典,然后我们将深入探讨字符串及其相关的操作和处理方法,包括格式化和切片。我们还将通过示例来详细解释如何使用这些结构和方法,以便你可以在实际编程中轻

热文推荐