首页 > 系统相关 >【Linux】信号

【Linux】信号

时间:2024-11-17 14:43:04浏览次数:3  
标签:cnt int 信号 Linux 进程 include define

文章目录

概要

Linux信号是一种进程间通信机制,它允许操作系统和进程之间进行事件通知、控制及管理。信号本质上是由操作系统内核发送给进程的异步消息,通常用于处理进程的状态改变、硬件中断或者异常情况。Linux系统中定义了多种信号,它们具有特定的功能和语义。

整体架构流程

在Linux系统中,信号机制的工作流程涉及信号的发送、接收和处理。信号的发送方通常是操作系统内核或其他进程,而接收方是目标进程。信号的处理通过信号处理程序(signal handler)实现,若目标进程没有自定义处理程序,系统会采取默认行为。

信号的发送与接收

  • 操作系统内核在检测到特定事件时,会向进程发送信号。
  • 信号通过内核的信号队列传递到进程的信号接收队列中。
  • 进程会在适当的时候(通常是在当前执行的系统调用或时间片切换时)接收信号。
  • 接收到信号后,进程根据信号类型执行相应的处理程序(如果有定义的话),否则按照默认行为处理信号。

信号的处理

  • 信号可以被进程处理,默认处理或忽略。处理信号的方式可以通过signal()系统调用来设置。
  • 如果一个信号没有被处理,系统会执行信号的默认行为。例如,SIGKILL会强制终止进程。
  • 对于某些信号,操作系统会将信号挂起,直到进程准备好处理信号为止。

技术名词解释

  • 信号(Signal):一种由操作系统发送给进程的异步通知,用于通知-进程发生了某些事件,如用户请求终止进程或硬件中断等。
  • 信号处理程序(Signal Handler):一个用户定义的函数,用于处理进程接收到的信号。当进程接收到信号时,如果定义了相应的信号处理程序,操作系统会跳转到该程序执行。
  • 默认行为:如果进程没有定义信号处理程序,则会按照操作系统预设的行为处理信号。例如,SIGKILL会强制杀死进程。
  • 信号屏蔽(Signal Masking):进程可以屏蔽某些信号,使其不被接收。通常通过sigprocmask()等函数来控制。

信号分析

查看信号

可以通过kill -l看出相关信号
在这里插入图片描述
1-31是非实时信号,34之后的是实时信号
可以查看手册,man 7 signal
在这里插入图片描述
在这里插入图片描述
注意到最下面的2个特殊信号的说明。

内核定义的信号。

#define SIGHUP		 1
#define SIGINT		 2
#define SIGQUIT		 3
#define SIGILL		 4
#define SIGTRAP		 5
#define SIGABRT		 6
#define SIGIOT		 6
#define SIGBUS		 7
#define SIGFPE		 8
#define SIGKILL		 9
#define SIGUSR1		10
#define SIGSEGV		11
#define SIGUSR2		12
#define SIGPIPE		13
#define SIGALRM		14
#define SIGTERM		15
#define SIGSTKFLT	16
#define SIGCHLD		17
#define SIGCONT		18
#define SIGSTOP		19
#define SIGTSTP		20
#define SIGTTIN		21
#define SIGTTOU		22
#define SIGURG		23
#define SIGXCPU		24
#define SIGXFSZ		25
#define SIGVTALRM	26
#define SIGPROF		27
#define SIGWINCH	28
#define SIGIO		29
#define SIGPOLL		SIGIO
/*
#define SIGLOST		29
*/
#define SIGPWR		30
#define SIGSYS		31
#define	SIGUNUSED	31

/* These should not be considered constants from userland.  */
#define SIGRTMIN	32
#define SIGRTMAX	(_NSIG-1)

可以看到,每个信号就是对应不同的数字。

信号的产生方式

  1. 通过键盘产生信号
  2. 通过终端按键产生信号
  3. 调用系统函数向进程发信号
  4. 由软件条件产生信号
  5. 硬件异常产生信号
键盘产生信号

测试代码块

#include <iostream>
#include <unistd.h>
using namespace std;

int main()
{
    while(true)
    {
        sleep(1);
        cout<<"I am main run"<<endl;
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
ctrl+c=2号信号SIGINT,ctrl+\=3号信号SIGQUIT。

终端按键产生信号

在这里插入图片描述
查到对应进程的pid。
在这里插入图片描述
用kill命令发送信号
在这里插入图片描述
看到进程被kill。
在这里插入图片描述

系统函数向进程发信号

查看对应的系统调用
在这里插入图片描述
示例代码

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
using namespace std;

int main()
{
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt"<<cnt<<endl;
        if(cnt == 5)
        {
            kill(getpid(),2);
        }
    }
    return 0;
}

查看运行结果
在这里插入图片描述
五秒后,进程收到2号信号,进程终止。

软件条件产生信号

使用一个闹钟软件信号来进行测试。
在这里插入图片描述
当到达指定时间,alarm就会给进程发送14号信号。
示例代码

#include <iostream>
#include <unistd.h>
using namespace std;

int main()
{
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt"<<cnt<<endl;
        if(cnt == 5)
        {
            alarm(5);
        }
    }
    return 0;
}

查看结果
在这里插入图片描述

硬件异常产生信号

硬件异常产生的信号和软件产生的信号有些不同。在信号处理函数再说。
示例代码

#include <iostream>
#include <unistd.h>
using namespace std;

int main()
{
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt"<<cnt<<endl;
        if(cnt == 5)
        {
            int a = 10;
            a/=0;
        }
    }
    return 0;
}

这里会发送除0异常。
在这里插入图片描述

信号处理函数

信号的处理有三种方式
1,忽略该信号
2,用户捕捉信号,执行用户所写的处理函数
3,执行默认的处理函数(这个不做演示)

认识一下捕捉函数
在这里插入图片描述
在这里插入图片描述

signal捕捉信号,第一个参数是需要捕捉的信号,可以是SIGINT也可以是2,第二个是回调处理函数,对应的回调函数的参数int就是传送的signum参数。返回值是以前的处理函数,这个是为了后续恢复之前的信号处理函数。

忽略信号

先看看如何定义忽略信号的

#define	SIG_ERR	 ((__sighandler_t) -1)	/* Error return.  */
#define	SIG_DFL	 ((__sighandler_t)  0)	/* Default action.  */
#define	SIG_IGN	 ((__sighandler_t)  1)	/* Ignore signal.  */

所以我们只需要在signal第二个参数传送SIG_IGN即可。
示例代码

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;

int main()
{
    signal(SIGINT,SIG_IGN);
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt"<<cnt<<endl;
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,2号信号已经被忽略,不做任何处理了。

回到上面的2个特殊信号,SIGKILL,SIGSTOP。这里测试SIGKILL
这2个信号都不能被捕捉,不能被忽略。

示例代码

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;

int main()
{
    signal(SIGKILL,SIG_IGN);
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt"<<cnt<<endl;
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,进程仍然被kill掉了。

自定义处理函数

需要我们设置一个处理函数。
示例代码

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;

void  handler(int signo)
{
    std::cout<<"get signo: "<<signo<<endl;
}
int main()
{
    signal(SIGFPE,handler);//这里选择的8号信号
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt: "<<cnt<<endl;
    }
    return 0;
}

查看现象
在这里插入图片描述
在这里插入图片描述
可以看到,程序执行了我们自己写的处理函数

SIGKILL仍然不能被捕获,只能执行自己的默认处理函数,这个也是为了系统安全。

这里就可以演示硬件信号的不同了。
示例代码

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;

void  handler(int signo)
{
    std::cout<<"get signo: "<<signo<<endl;
}
int main()
{
    signal(SIGFPE,handler);
    int cnt = 0;
    while(true)
    {
        cnt++;
        sleep(1);
        cout<<"I am main run:cnt: "<<cnt<<endl;
        if(cnt = 5)
        {
            int a = 10;
            a/=0;
        }
    }
    return 0;
}

查看现象
在这里插入图片描述
这里是无限死循环的执行信号处理函数。分析原因

当程序碰到除0异常,硬件发出信号,进程执行完处理函数之后,回到程序运行的地方,此时硬件发现仍然存在除0异常,则继续让进程执行处理函数,从而无限执行。

信号的执行流程

转接到这篇博客

信号执行流程

小结

Linux信号机制是操作系统与进程之间重要的异步通信手段,它能够在进程之间传递重要的事件通知。信号不仅可以控制进程的执行,还能在进程遇到异常或其他关键事件时触发适当的响应。通过灵活地设置信号处理程序,开发者可以自定义进程的行为,响应系统的需求,确保程序的稳定和可靠性。理解信号的使用和相关技术,能够帮助开发者更好地实现进程管理和控制。

标签:cnt,int,信号,Linux,进程,include,define
From: https://blog.csdn.net/2201_75443644/article/details/143796590

相关文章

  • 对比 win32 linux原生 和 qt 的 所有 socket api
    以下是Win32原生、Linux原生和Qt的SocketAPI对比,包括TCP和UDP的功能、特性及优缺点。我们从核心API、特性、性能和常见应用等方面进行分析。1.核心API对比1.1Socket创建与初始化操作Win32(原生)Linux(原生)Qt(跨平台)创建套接字socket()socket()......
  • ssh配置密钥登录linux
    1、生成sshkey示例ssh-keygen-trsa2、将生成的公钥内容拷贝到linux服务器的~/.ssh/authorized_keys如果是root用户,那就放在根目录的.ssh目录下,如果是其它用户,放置在用户目录的.ssh目录下3、在本机.ssh目录下,创建config文件,内容如下Hostdata01.rootHostNam......
  • 【Linux之权限】理论篇
    前言Linux的权限是我们学习Linux初期非常重要的基础知识,接下来我将通过一个系列【Linux之权限】,共三篇文章,对此进行较为全面和详细的解说。sudo情况:如果我们不是超级管理员,但是想执行一个权限级别比较高的指令,比如我们想以超级管理员的身份来创建一个文件,那么就:sudotou......
  • 这款信创CAD Linux与麒麟国产系统高效适配,荣获麒麟用户挚爱奖
    本文为CAD芯智库原创,未经允许请勿复制、转载!原文转自:www.xwzsoft.com/h-nd-493.html信创国产化发展至今已经陆续取得不少突破,作为工程建设/工业制造企业的核心设计/生产软件之一,CAD对国产信创操作系统、硬件设备的适配度发展也至关重要。对此,中望2016就开始投入CAD......
  • Linux 实例:配置 NTP 服务
    网络时间协议(NetworkTimeProtocol,NTP),用于同步网络中各个计算机的时间的协议。其用途是将计算机的时钟同步到世界协调时UTC。腾讯云提供了内网NTP服务器供腾讯云内网设备使用,对于非腾讯云设备,可以使用腾讯云提供的公网NTP服务器。操作场景ntpd(NetworkTimeProtocold......
  • Linux开发工具:Vim 与 gcc,打造高效编程的魔法双剑
    文章目录一、初识Vim模式二、vim基本操作2.1基础操作2.2命令模式/正常模式2.2.1光标定位2.2.2复制粘贴、删除2.2.3撤销2.2.4替换字符2.2.5替换模式2.3底行模式2.3.1退出vim和**保存文件**2.3.2定位文本字符串2.3.3命令2.3.4实现分屏2.3.5替换指定字符串2.4补充指令2.4......
  • Linux
    LinuxLinux系统启动过程Linux关机不管是重启系统还是关闭系统,首先要运行sync命令,把内存中的数据写到磁盘中。关机的命令有shutdown–hnow,halt,poweroff和init0,重启系统的命令有shutdown–rnow,reboot,init6。图形模式与文字模式的切换方式命令窗口切换的......
  • [Linux]gdb基本使用
    gdb基本使用前提gcc/g++编译出的程序默认是realease版本,要使用gdb调试,首先要在编译的时候加上-g选项。使用readelf-S[程序名]查看可执行文件的节区信息。使用gdb[程序名]:开始调试。q:退出调试。list/l[行号]:从给定的位置显示程序的源代码,每次十行。break/b......
  • 轻松理解操作系统 - Linux文件系统模块完结!又可以快速了解原理了
    在前面的7期中,我们了解了Linux文件系统的模块和它们相互之间是如何配合并形成一个完整的、可以将所有的所有都抽象成文件的体系。这样的体系主要是为了帮助大家在使用或编程的时候更加的简化,从而更简单的使用以及提升效率。本篇文章则提升深入理解Linux文件系统的效率,......
  • 轻松理解操作系统 - 图文:Linux内核虚拟内存的基石是什么?
    第一大模块:一文串联文件系统模块上期文章中,我们了解了 Linux内存管理模块 的其中一大功能:内核虚拟内存管理。内核的虚拟内存是怎么管理的?内核虚拟内存的管理是用户程序创建进程和执行各种任务的基础。没有它,我们就无法正常使用系统。但,虚拟内存终究是要落到物理内存里面的......