Linux笔记---信号(上)

1. 信号的概念

Linux下的信号机制是一种进程间通信(IPC)的方式,用于在不同进程之间传递信息。

信号是一种异步的信息传递方式,这意味着发送信号的进程只发送由信号作为载体的命令,而并不关心接收信号的进程如何处置这个命令(做不做、何时做、怎么做、结果如何等)。

这样,在发送完命令之后,发送命令的进程就可以着手自己的其他任务,而无需等待对方反馈的结果(或者说无需与对方进行同步)。同时也就意味着接收信号的进程对于命令的处置是相对自由的,甚至可以直接忽略。

例如,菜鸟驿站给你发消息告诉你包裹到了(这就是一种信号),你可以去取,也可以不取(富哥不想要了,又懒得退款,或者单纯忘了);你可以立即去取,也可以等几个小时/几天再取;你可以自己去取,也可以叫好友帮取,甚至叫个跑腿去取。

但有时候我们又希望自己发送的信号是绝对有效的,不可被轻视的。于是,我们可以将信号分为可靠信号和不可靠信号,一共62种(1~64,除开32和33):

  • 不可靠信号:也称为非实时信号,不支持排队,信号可能会丢失。比如发送多次相同的信号,进程只能收到一次,信号值取值区间为1~31。

  • 可靠信号:也称为实时信号,支持排队,信号不会丢失,发多少次,就可以收到多少次,信号值取值区间为34~64。

使用 [ kill -l ] 指令可以进行查看: 

2. 信号的处理

2.1 默认处理

每个信号都有默认的处理方式,如SIGINT信号的默认处理是终止进程,SIGTERM信号的默认处理也是终止进程,SIGSEGV信号的默认处理是产生核心转储并终止进程。

man 7 signal

找到标题:Standard signals

  • Core(核心转储并终止进程):如SIGABRT、SIGFPE信号,当这些信号发生时,系统会进行核心转储并且终止进程。
  • Term(终止进程):像SIGALRM、SIGHUP信号,这些信号的默认动作是终止进程。
  • Ign(忽略信号):对于SIGCHLD、SIGCLD信号,系统默认会忽略这些信号。
  • Cont(继续执行):对于SIGCONT信号,其默认动作是如果进程处于停止状态则继续执行。
  • Stop(停止进程):对于SIGSTOP信号,它会使进程停止执行,且不能被捕获、忽略或阻塞。

可以看到,大多数信号的默认处理方式都是终止进程。

2.2 捕获信号

进程可以通过设置信号处理函数来捕获信号并执行自定义的处理逻辑。例如,可以在信号处理函数中记录日志、进行资源清理等操作。

#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);

功能

设置信号处理程序signal函数用于设置一个函数来处理特定的信号。当指定的信号发生时,系统会调用相应的信号处理函数。

参数

sig:表示要处理的信号码。常见的信号常量包括SIGABRT(程序异常终止)、SIGFPE(算术运算出错)、SIGILL(非法指令)、SIGINT(中断信号,如Ctrl+C)、SIGSEGV(非法访问存储器)、SIGTERM(终止请求)等。

func:是一个指向函数的指针,用于指定信号处理程序。可以是自定义的函数,也可以是以下预定义函数之一:

  • SIG_DFL:表示使用该信号的默认处理程序。

  • SIG_IGN:表示忽略该信号。

返回值

成功时:返回信号处理程序之前的值。

出错时:返回SIG_ERR

例如,我们编写一个循环打印 hello world 的程序, 并让他捕获2号信号,即ctrl + c发出的信号:

#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>void SigHandler(int sigid)
{std::cout << "获得信号: " << sigid << std::endl;exit(sigid);
}int main()
{signal(SIGINT, SigHandler);for(int i = 0; true; i++){std::cout << "Hello World[" << i << "]" << ", pid:["  << getpid() << "]" << std::endl;sleep(1);}return 0;
}

当我们在程序运行的过程中按下 ctrl + c 时,程序会显示获得信号:

2.3 忽略信号

进程可以通过设置信号处理函数为SIG_IGN来忽略某个信号。但有些信号是不能被忽略的,如SIGKILLSIGSTOP信号。

3. 信号的产生方式

  • 用户输入:用户在终端输入特定的快捷键组合,如Ctrl+C会产生SIGINT信号,Ctrl+\会产生SIGQUIT信号,Ctrl+Z会产生SIGTSTP信号。

  • 程序执行异常:当程序执行过程中出现错误或异常情况时,内核会发送相应的信号。例如,对一个数除0会产生SIGFPE信号,非法访问一段内存会产生SIGBUS信号,访问未分配的虚拟内存会产生SIGSEGV信号。

  • 进程间发送信号:一个进程可以通过系统调用向另一个进程发送信号。例如,使用kill函数可以向指定进程发送信号,raise函数可以向本进程发送信号,sigqueue函数可以向一个进程发送信号并传递额外数据。

用户输入方式我们在前面已经见识过,就不再多说。

3.1 程序执行异常

我们的程序在遇到运行时错误时会报错并退出,这就是因为程序在发生执行异常时会引发硬件异常中断,操作系统检测到之后,就会向引发异常的进程发送一个信号,进而终止进程。

下面的代码中,我们尝试捕捉由除零引发的异常和使用野指针引发的异常:

#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>void SigHandler(int sigid)
{std::cout << "获得信号: " << sigid << std::endl;exit(sigid);
}int main()
{for(int i = 1; i < 32; i++){signal(i, SigHandler);}// 8) SIGFPEint a = 10;a /= 0;// 11) SIGSEGV// int *p = nullptr;// *p = 100;return 0;
}

除零异常导致程序退出:

使用野指针导致程序退出:

3.2 进程间发送信号

3.2.1 kill命令
kill -[信号编号] [指定进程pid]

 在命令行使用kill指令可像指定进程发送指定信号。

3.2.2 kill函数
#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);

功能

kill函数用于向指定的进程或进程组发送信号,以实现进程间的通知或控制。

参数

  • pid:表示要发送信号的目标进程或进程组的标识符。

    • pid > 0:将信号发送给进程标识为pid的进程。

    • pid = 0:将信号发送给与调用kill函数的进程属于同一进程组的所有进程。

    • pid = -1:将信号发送给除了进程1(init进程)和调用者自身以外的所有进程。

    • pid < -1:将信号发送给进程组ID等于pid绝对值的所有进程。

  • sig:表示要发送的信号。可以是以下常见信号常量之一

返回值

  • 成功时:返回0。

  • 出错时:返回-1,并设置errno以指示错误原因。

 3.2.3 raise函数
#include <signal.h>int raise(int sig);
  • 功能:向调用该函数的进程发送一个信号(即向自己发送信号)。

  • 参数sig表示要发送的信号编号。

  • 返回值:成功时返回0;失败时返回非0值。

#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>void SigHandler(int sigid)
{std::cout << "获得信号: " << sigid << std::endl;exit(sigid);
}int main()
{for(int i = 1; i < 32; i++){signal(i, SigHandler);}for(int i = 1; i < 32; i++){sleep(1);// 给自己发信号if(i == 9 || i == 19) // 9-SIGKILL 19-SIGSTOP不能被自定义捕获 continue;raise(i);}return 0;
}

 9号信号SIGKILL和19号信号SIGSTOP无法被自定义捕获,这是为了防止出现所有信号都被捕获而无法通过信号使目标进程被强制停止的情况。

3.2.4 abort函数
#include <stdlib.h>void abort(void);

功能abort函数用于立即终止当前程序的执行,通常在检测到不可恢复的错误时使用。

特点

  • 不执行清理工作abort函数不会执行任何atexit注册的函数或对象析构函数,也不会刷新流缓冲区或关闭打开的文件等常规清理操作。

  • 产生核心转储文件:在某些系统上,如果系统配置允许,abort函数会产生一个核心转储文件,用于调试程序异常终止的原因。

  • 发送信号abort函数会向调用进程发送SIGABRT信号,进程不应忽略此信号。

3.2.5 sigqueue函数

功能:向指定的进程发送特定的信号,并可以传递一个额外的数据值,提供了比kill函数更丰富的功能,可用于进程间的高级通信。

暂时不做介绍。

4. 补充:前后台进程

在大多数用户交互式操作系统当中,都会把进程分为前台进程和后台进程,在Linux中二者的概念如下:

  • 前台进程:是与用户直接交互的进程,占有控制终端,可以从终端接收输入并向终端发送输出。在任何时刻,只有一个进程组可以在前台运行。

  • 后台进程:是不与用户直接交互的进程,在后台默默运行,不占用控制终端。

用户在命令行启动可执行程序时,该可执行程序默认以前台方式运行,由于前台进程只有一个,所以操作系统会将bash切换到后台运行,待可执行程序运行结束或者被切换到后台时,再将bash切换回前台。

如果用户希望进程被启动后在后台运行,可在其后跟上 & :

可以看到,我们让SigTest运行起来之后,bash和SigTest都在往标准输出打印,当我们输入ls指令之后,发现处于前台的bash获得了我们的输入,并运行了ls。

此时,如果我们想要通过[ctrl + c]的方式来结束SigTest是行不通的,因为只有前台进程能接收到我们的输入。此时我们有两种做法:

  • 使用kill -9指定终止SigTest。
  • 将SigTest放到前台,再使用[ctrl + c]。

前者不再进行说明了,接下来我们讲解一下如何在命令行控制进程的前后台切换。

在Linux中,与前后台相关的指令主要用于管理进程的运行状态,以下是一些常用的指令:

后台运行指令

  • &:在命令末尾添加“&”符号,可以使程序在后台运行,例如“./matmul &”将运行一个名为matmul的程序并使其在后台运行,这样用户就可以在前台继续执行其他命令。
  • nohup:nohup命令用于在后台运行命令,即使终端关闭或用户退出,命令也会继续执行。例如,“nohup ping 101.lug.ustc.edu.cn &”将在后台运行ping命令,并将输出重定向到nohup.out文件中。

前后台切换指令

  • Ctrl+Z:将当前正在前台执行的命令或进程暂停,并放入后台。例如,当一个命令在前台运行时,按下Ctrl+Z,该命令将被暂停并放入后台,屏幕上会显示相关的状态信息。
  • jobs:用于查看当前在后台运行的进程或任务的列表,以及它们的状态和作业号。例如,“jobs -l”将显示详细的后台进程信息,包括进程ID、状态等。
  • fg:将后台中的进程调至前台继续运行。例如,“fg %1”将把后台中作业号为1的进程调至前台运行。
  • bg:将后台中暂停的进程继续在后台运行。例如,“bg %2”将使后台中作业号为2的进程在后台继续运行。

其他相关指令

  • ps:用于查看当前系统中正在运行的进程的状态和信息。例如,“ps aux”将显示所有用户的所有进程的详细信息。
  • kill:用于向进程发送信号,通常用于终止进程。例如,“kill -9 PID”将强制终止指定PID的进程。
  • top:用于实时查看系统中各个进程的资源占用情况,包括CPU、内存等。
  • htop:是top命令的增强版,提供了更直观和交互性更强的界面,用于查看和管理进程。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/80687.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UG 二次开发- UG内部调用DLL

【1】用VS新建一个dll工程 将项目设置为x64平台&#xff08;这步很重要&#xff0c;否则程序无法编译成功&#xff09; 【2】添加UG头文件目录&#xff0c;属性页->C/C->常规->附加包含目录 【3】添加UG库所在目录&#xff0c;属性页->链接器->常规->附加库目…

wordcount在mapreduce的例子

1.启动集群 2.创建项目 项目结构为&#xff1a; 3.pom.xml文件为 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://mave…

智慧城市综合运营管理系统Axure原型

这款Axure原型的设计理念紧紧围绕城市管理者的需求展开。它旨在打破传统城市管理中信息孤岛的局面&#xff0c;通过统一标准接入各类业务系统&#xff0c;实现城市运营管理信息资源的全面整合与共享。以城市管理者为中心&#xff0c;为其提供一个直观、便捷、高效的协同服务平台…

Go语言:json 作用和语法

在 Go 语言中&#xff0c;JSON 字段&#xff08;也称为 JSON Tag&#xff09;是附加在结构体字段上的元数据&#xff0c;用于控制该字段在 JSON 编码&#xff08;序列化&#xff09;和解码&#xff08;反序列化&#xff09; 时的行为。它的语法是&#xff1a; type StructName…

MATLAB复制Excel数据到指定区域

Matlab中如何将Excel表中的265-528行F-AA列数据复制到1-263行AE-AZ中 版本&#xff1a;MatlabR2018b clc; clear; %旧Excel文件名 oldFile ; %新Excel文件名 newFile ; % 工作表名称&#xff08;旧表和新表一致&#xff09; sheetName Sheet1; % 旧文件中待复制的数据范…

vue3+flask+sqlite前后端项目实战

基础环境安装 pycharm 下载地址&#xff1a; https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows vscode 下载地址 https://code.visualstudio.com/docs/?dvwin64user python 下载地址 https://www.python.org/downloads/windows/ Node.js&#xff08;含npm…

Java 内存模型(JMM)与内存屏障:原理、实践与性能权衡

Java 内存模型&#xff08;JMM&#xff09;与内存屏障&#xff1a;原理、实践与性能权衡 在多线程高并发时代&#xff0c;Java 内存模型&#xff08;JMM&#xff09; 及其背后的内存屏障机制&#xff0c;是保障并发程序正确性与性能的基石。本文将系统梳理 JMM 的核心原理、内…

动手学深度学习12.3.自动并行-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;无 本节教材地址&#xff1a;12.3. 自动并行 — 动手学深度学习 2.0.0 documentation 本节开源代…

C++类和对象之初始化列表

初始化列表 C初始化列表详解&#xff1a;性能优化与正确实践什么是初始化列表&#xff1f;初始化列表的三大核心作用1. 性能优化&#xff1a;避免不必要的赋值操作2. 强制初始化&#xff1a;处理const和引用成员3. 基类初始化&#xff1a;正确调用父类构造函数4.必须使用初始化…

continue通过我们的开源 IDE 扩展和模型、规则、提示、文档和其他构建块中心,创建、共享和使用自定义 AI 代码助手

​一、软件介绍 文末提供程序和源码下载 Continue 使开发人员能够通过我们的开源 VS Code 和 JetBrains 扩展以及模型、规则、提示、文档和其他构建块的中心创建、共享和使用自定义 AI 代码助手。 二、功能 Chat 聊天 Chat makes it easy to ask for help from an LLM without…

基于Spring Boot + Vue的母婴商城系统( 前后端分离)

一、项目背景介绍 随着母婴行业在互联网平台的快速发展&#xff0c;越来越多的家庭倾向于在线选购母婴产品。为了提高商品管理效率和用户购物体验&#xff0c;本项目开发了一个基于 Spring Boot Vue 技术栈的母婴商城系统&#xff0c;实现了商品分类、商品浏览、资讯展示、评…

实战演练:用 AWS Lambda 和 API Gateway 构建你的第一个 Serverless API

实战演练:用 AWS Lambda 和 API Gateway 构建你的第一个 Serverless API 理论千遍,不如动手一遍!在前面几篇文章中,我们了解了 Serverless 的概念、FaaS 的核心原理以及 BaaS 的重要作用。现在,是时候把这些知识运用起来,亲手构建一个简单但完整的 Serverless 应用了。 …

node.js 实战——express图片保存到本地或服务器(七牛云、腾讯云、阿里云)

本地 ✅ 使用formidable 读取表单内容 npm i formidable ✅ 使用mime-types 获取图片后缀 npm install mime-types✅ js 中提交form表单 document.getElementById(uploadForm).addEventListener(submit, function(e){e.preventDefault();const blob preview._blob;if(!blob)…

2025最新:3分钟使用Docker快速部署单节点Redis

&#x1f9d1;‍&#x1f3eb; 详细教程&#xff1a;通过 Docker 安装单节点 Redis &#x1f6e0;️ 前提条件&#xff1a; 你需要在 Ubuntu 系统上进行操作&#xff08;如果你在其他系统上操作&#xff0c;可以按相似步骤进行调整&#xff09;。已安装 Docker 和 Docker Com…

CentOS 7 系统下安装 OpenSSL 1.0.2k 依赖问题的处理

前面有提到过这个openssl的版本冲突问题&#xff0c;也是在这次恢复服务器时遇到的问题&#xff0c;我整理如下&#xff0c;供大家参考。小小一个软件的安装&#xff0c;挺坑的。 一、问题 项目运行环境需要&#xff0c;指定PHP7.0.9这个版本&#xff0c;但是‌系统版本与软件…

LoRA(Low-Rank Adaptation)原理详解

LoRA(Low-Rank Adaptation)原理详解 LoRA(低秩适应)是一种参数高效微调(Parameter-Efficient Fine-Tuning, PEFT)技术,旨在以极低的参数量实现大模型在特定任务上的高效适配。其核心思想基于低秩分解假设,即模型在适应新任务时,参数更新矩阵具有低秩特性,可用少量参…

Solana批量转账教程:提高代币持有地址和生态用户空投代币

前言 Solana区块链因其高吞吐量和低交易费用成为批量操作&#xff08;如空投&#xff09;的理想选择。本教程将介绍几种在Solana上进行批量转账的方法&#xff0c;帮助您高效地向多个地址空投代币。 solana 账户模型 在Solana中有三类账户&#xff1a; 数据账户&#xff0c;…

基于LSTM与SHAP可解释性分析的神经网络回归预测模型【MATLAB】

基于LSTM与SHAP可解释性分析的神经网络回归预测模型【MATLAB】 一、引言 在数据驱动的智能时代&#xff0c;时间序列预测已成为许多领域&#xff08;如金融、气象、工业监测等&#xff09;中的关键任务。长短期记忆网络&#xff08;LSTM&#xff09;因其在捕捉时间序列长期依…

手机网页提示ip被拉黑名单什么意思?怎么办

‌当您使用手机浏览网页时&#xff0c;突然看到“您的IP地址已被列入黑名单”的提示&#xff0c;是否感到困惑和不安&#xff1f;这种情况在现代网络生活中并不罕见&#xff0c;但确实会给用户带来诸多不便。本文将详细解释IP被拉黑的含义、常见原因&#xff0c;并提供一系列实…

Java消息队列性能优化实践:从理论到实战

Java消息队列性能优化实践&#xff1a;从理论到实战 1. 引言 在现代分布式系统架构中&#xff0c;消息队列&#xff08;Message Queue&#xff0c;MQ&#xff09;已经成为不可或缺的中间件组件。它不仅能够实现系统间的解耦&#xff0c;还能提供异步通信、流量削峰等重要功能…