无涯教程-进程 - 信号(Signals)

信号是对进程的通知,指示事件的发生。信号也称为软件中断,无法预知其发生,因此也称为异步事件。

可以用数字或名称指定信号,通常信号名称以SIG开头。可用信号kill –l(列出信号名称为l)检查可用信号,如下所示-

Signal

无论何时发出信号,都会执行默认操作,忽略信号意味着既不执行默认操作也不处理信号,几乎可以忽略或处理所有信号。不可忽略或无法处理/捕获的信号是SIGSTOP和SIGKILL。

总而言之,对信号执行的操作如下-

  • 默认操作
  • 处理信号
  • 忽略信号

如所讨论的,可以改变默认动作的执行来处理信号,信号处理可以两种方式之一进行,即通过系统调用signal()和sigaction()。

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

系统调用signal()将在信号产生时调用注册处理程序,如信号传递中所述。处理程序可以是SIG_IGN(忽略信号),SIG_DFL(将信号设置回默认机制)或用户定义的信号处理程序或函数地址之一。

成功的系统调用将返回带有整数参数且没有返回值的函数的地址。如果发生错误,此调用将返回SIG_ERR。

尽管可以使用signal()调用由用户注册的相应信号处理程序,但无法进行微调,例如屏蔽应阻止的信号,修改信号的行为以及其他功能。使用sigaction()系统调用可以做到这一点。

#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)

该系统调用用于检查或更改信号动作,如果该动作不为空,则从该动作安装信号信号的新动作。如果oldact不为null,则先前的操作将保存在oldact中。

sigaction结构包含以下字段-

字段1  -  在sa_handler或sa_sigaction中提到的处理程序。

void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);

sa_handler的处理程序基于符号指定要执行的操作,其中SIG_DFL表示默认操作,而SIG_IGN则忽略信号或指向信号处理功能的指针。

sa_sigaction的处理程序将信号编号指定为第一个参数,将siginfo_t结构的指针指定为第二个参数,将用户上下文的指针指定为第三个参数(请检查getcontext()或setcontext()以获取更多信息)。

结构siginfo_t包含信号信息,例如要传送的信号编号,信号值,进程ID,发送进程的实际用户ID等。

字段2   -  要阻止的信号集。

int sa_mask;

此变量指定在执行信号处理程序期间应屏蔽的信号掩码。

字段3  -  特殊标志。

int sa_flags;

该字段指定一组标志,这些标志可修改信号的行为。

字段4  -  还原处理程序。

void (*sa_restorer) (void);

成功时此系统调用返回0,失败时返回-1。

让我们考虑一些示例程序。

首先,让我们从产生异常的示例程序开始,在此程序中,我们尝试执行零除运算,这会使系统生成异常。

/* signal_fpe.c */
#include<stdio.h>int main() {int result;int v1, v2;v1 = 121;v2 = 0;result = v1/v2;printf("Result of Divide by Zero is %d\n", result);return 0;
}

编译和执行步骤

Floating point exception (core dumped)

因此,当我们尝试执行算术运算时,系统生成了带有核心转储的浮点异常,这是信号的默认操作。

现在,让我们使用signal()系统调用来修改代码以处理此特定信号。

/* signal_fpe_handler.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>void handler_dividebyzero(int signum);int main() {int result;int v1, v2;void (*sigHandlerReturn)(int);sigHandlerReturn = signal(SIGFPE, handler_dividebyzero);if (sigHandlerReturn == SIG_ERR) {perror("Signal Error: ");return 1;}v1 = 121;v2 = 0;result = v1/v2;printf("Result of Divide by Zero is %d\n", result);return 0;
}void handler_dividebyzero(int signum) {if (signum == SIGFPE) {printf("Received SIGFPE, Divide by Zero Exception\n");exit (0);} elseprintf("Received %d Signal\n", signum);return;
}

编译和执行步骤

Received SIGFPE, Divide by Zero Exception

如所讨论的,信号是由系统生成的,或者用户也可以通过编程方式生成信号,如果要以编程方式生成信号,请使用库函数raise()。

要继续执行已停止的进程,请将SIGCONT发送到该特定进程。您还可以发出fg(前景)或bg(背景)命令以继续执行,在这里,这些命令只会重新开始最后一个进程的执行。如果停止了多个进程,则仅恢复最后一个进程。如果要恢复以前停止的进程,请恢复作业(使用fg/bg)以及作业号。

以下程序用于通过raise()函数引发信号SIGSTOP。用户按下CTRL + Z(Control + Z)键也可以生成信号SIGSTOP。发出该信号后,程序将停止执行。发送信号(SIGCONT)以继续执行。

在以下示例中,我们将使用命令fg恢复停止的进程。

/* signal_raising.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>int main() {printf("Testing SIGSTOP\n");raise(SIGSTOP);return 0;
}

编译和执行步骤

Testing SIGSTOP
[1]+ Stopped ./a.out
./a.out

现在,通过从另一个终端发出SIGCONT,增强先前的程序以继续执行已停止的进程。

/* signal_stop_continue.c */
#include<stdio.h>
#include<signal.h>
#include <sys/types.h>
#include <unistd.h>void handler_sigtstp(int signum);int main() {pid_t pid;printf("Testing SIGSTOP\n");pid = getpid();printf("Open 另一个码头 and issue following command\n");printf("kill -SIGCONT %d or kill -CONT %d or kill -18 %d\n", pid, pid, pid);raise(SIGSTOP);printf("Received signal SIGCONT\n");return 0;
}

编译和执行步骤

Testing SIGSTOP
Open 另一个码头 and issue following command
kill -SIGCONT 30379 or kill -CONT 30379 or kill -18 30379
[1]+ Stopped ./a.outReceived signal SIGCONT
[1]+ Done ./a.out

在另一个终端

kill -SIGCONT 30379

到目前为止,我们已经看到了处理系统生成的信号的程序。现在,让我们看看通进程序(使用raise()函数或通过kill命令)生成的信号。该程序生成信号SIGTSTP(终端停止),其默认操作是停止执行。但是,由于我们现在正在处理信号而不是默认操作,因此它将到达已定义的处理程序。在这种情况下,我们只是打印消息并退出。

/* signal_raising_handling.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>void handler_sigtstp(int signum);int main() {void (*sigHandlerReturn)(int);sigHandlerReturn = signal(SIGTSTP, handler_sigtstp);if (sigHandlerReturn == SIG_ERR) {perror("Signal Error: ");return 1;}printf("Testing SIGTSTP\n");raise(SIGTSTP);return 0;
}void handler_sigtstp(int signum) {if (signum == SIGTSTP) {printf("Received SIGTSTP\n");exit(0);}elseprintf("Received %d Signal\n", signum);return;
}

编译和执行步骤

Testing SIGTSTP
Received SIGTSTP

我们已经看到了执行默认操作或处理信号的实例。现在,该忽略信号了。在这里,在此示例程序中,我们通过SIG_IGN注册了要忽略的信号SIGTSTP,然后提高了信号SIGTSTP(终端停止)。当信号SIGTSTP产生时,将被忽略。

/* signal_raising_ignoring.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>void handler_sigtstp(int signum);int main() {void (*sigHandlerReturn)(int);sigHandlerReturn=signal(SIGTSTP, SIG_IGN);if (sigHandlerReturn == SIG_ERR) {perror("Signal Error: ");return 1;}printf("Testing SIGTSTP\n");raise(SIGTSTP);printf("Signal SIGTSTP is ignored\n");return 0;
}

编译和执行步骤

Testing SIGTSTP
Signal SIGTSTP is ignored

到目前为止,我们已经观察到我们有一个信号处理程序来处理一个信号。我们可以有一个处理程序来处理多个信号吗?答案是肯定的。让我们考虑一个程序。

以下程序执行以下操作-

步骤1  -   注册一个处理程序(handleSignals)以捕获或处理信号SIGINT(CTRL + C)或SIGQUIT(CTRL +\)

步骤2  -   如果用户生成信号SIGQUIT(通过终止命令或使用CTRL +\的键盘控制),则处理程序仅将消息打印为返回。

步骤3  -   如果用户首次生成信号SIGINT(通过kill命令或使用CTRL + C的键盘控制),则它将修改该信号以从下一次执行默认操作(使用SIG_DFL)。

步骤4  -   如果用户第二次生成信号SIGINT,它将执行默认操作,即终止程序。

/* Filename: sigHandler.c */
#include<stdio.h>
#include<unistd.h>
#include<signal.h>void handleSignals(int signum);int main(void) {void (*sigHandlerInterrupt)(int);void (*sigHandlerQuit)(int);void (*sigHandlerReturn)(int);sigHandlerInterrupt = sigHandlerQuit = handleSignals;sigHandlerReturn = signal(SIGINT, sigHandlerInterrupt);if (sigHandlerReturn == SIG_ERR) {perror("signal error: ");return 1;}sigHandlerReturn = signal(SIGQUIT, sigHandlerQuit);if (sigHandlerReturn == SIG_ERR) {perror("signal error: ");return 1;}while (1) {printf("\nTo terminate this program, perform the following:\n");printf("1. Open another terminal\n");printf("2. Issue command: kill %d or issue CTRL+C 2 times (second time it terminates)\n", getpid());sleep(10);}return 0;
}void handleSignals(int signum) {switch(signum) {case SIGINT:printf("\nYou pressed CTRL+C\n");printf("Now reverting SIGINT signal to default action\n");signal(SIGINT, SIG_DFL);break;case SIGQUIT:printf("\nYou pressed CTRL+\\\n");break;default:printf("\nReceived signal number %d\n", signum);break;}return;
}

编译和执行步骤

To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 74 or issue CTRL+C 2 times (second time it terminates)
^C
You pressed CTRL+C
Now reverting SIGINT signal to default actionTo terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 74 or issue CTRL+2 times (second time it terminates)
^\You pressed CTRL+\
To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 120
Terminated

另一个终端

kill 71

第二种方法

我们知道要处理信号,我们有两个系统调用,即signal()或sigaction()。到目前为止,我们已经看到了signal()系统调用,现在是时候进行sigaction()系统调用了。让我们修改上述程序以使用sigaction()如下执行-

/* Filename: sigHandlerSigAction.c */
#include<stdio.h>
#include<unistd.h>
#include<signal.h>void handleSignals(int signum);int main(void) {void (*sigHandlerReturn)(int);struct sigaction mysigaction;mysigaction.sa_handler = handleSignals;sigemptyset(&mysigaction.sa_mask);mysigaction.sa_flags = 0;sigaction(SIGINT, &mysigaction, NULL);if (mysigaction.sa_handler == SIG_ERR) {perror("signal error: ");return 1;}mysigaction.sa_handler = handleSignals;sigemptyset(&mysigaction.sa_mask);mysigaction.sa_flags = 0;sigaction(SIGQUIT, &mysigaction, NULL);if (mysigaction.sa_handler == SIG_ERR) {perror("signal error: ");return 1;}while (-1) {printf("\nTo terminate this program, perform either of the following:\n");printf("1. Open another terminal and issue command: kill %d\n", getpid());printf("2. Issue CTRL+C 2 times (second time it terminates)\n");sleep(10);}return 0;
}void handleSignals(int signum) {switch(signum) {case SIGINT:printf("\nYou have entered CTRL+C\n");printf("Now reverting SIGINT signal to perform default action\n");signal(SIGINT, SIG_DFL);break;case SIGQUIT:printf("\nYou have entered CTRL+\\\n");break;default:printf("\nReceived signal number %d\n", signum);break;}return;
}

让我们看看编译和执行进程。在执行进程中,让我们两次查看CTRL + C问题,其余检查/方式(如上所述)也可以尝试该程序。

编译和执行步骤

To terminate this program, perform either of the following:
1. Open another terminal and issue command: kill 3199
2. Issue CTRL+C 2 times (second time it terminates)
^C
You have entered CTRL+C
Now reverting SIGINT signal to perform default action
To terminate this program, perform either of the following:
1. Open another terminal and issue command: kill 3199
2. Issue CTRL+C 2 times (second time it terminates)
^C

进程 - 信号(Signals) - 无涯教程网无涯教程网提供信号是对进程的通知,指示事件的发生。信号也称为软件中断,无法预知其发生,因此也称...https://www.learnfk.com/process/inter-process-communication-signals.html

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

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

相关文章

骨传导耳机和普通耳机哪个危害大?一文读懂骨传导耳机!

作为一个5年重度运动爱好者&#xff0c;常年跑步、爬山、骑行&#xff0c;入手过的各类耳机超30款&#xff0c;用真实体验告诉大家&#xff0c;骨传导耳机和普通耳机哪个危害大&#xff01; 首先大家要知道的是&#xff0c;不管什么类型的耳机&#xff0c;如说说音量过大&…

SpringBoot生成和解析二维码完整工具类分享(提供Gitee源码)

前言&#xff1a;在日常的开发工作当中可能需要实现一个二维码小功能&#xff0c;我参考了网上很多关于SpringBoot生成二维码的教程&#xff0c;最终还是自己封装了一套完整生成二维码的工具类&#xff0c;可以支持基础的黑白二维码、带颜色的二维码、带Logo的二维码、带颜色和…

Spring Cloud Alibaba-Sentinel-Sentinel入门

1 什么是Sentinel Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。Sentinel 具有以下特征: 丰富的应用场景&#xff1a;Sentinel 承接了阿里…

【深度学习】实验02 鸢尾花数据集分析

文章目录 鸢尾花数据集分析决策树K-means 鸢尾花数据集分析 决策树 # 导入机器学习相关库 from sklearn import datasets from sklearn import treeimport matplotlib.pyplot as plt import numpy as np# Iris数据集是常用的分类实验数据集&#xff0c; # 由Fisher, 1936收集…

JetBrains 2023.2全新发布!IDEA、PyCharm等支持AI辅助

日前JetBrains官方正式宣布旗下IDE系列今年第二个重要版本——v2023.2全新发布&#xff0c;涵盖了 IntelliJ IDEA、PyCharm、WebStorm等一众知名产品&#xff0c;接下来我们一起详细了解一下他们的更新重点吧~ IntelliJ IDEA v2023.2——引入AI辅助开发 IntelliJ IDEA 2023.2…

动捕设备助力打造沉浸式虚拟现实体验

在纪录片《超时空寻找》中&#xff0c;借助了实时动捕设备&#xff0c;基于三维数字人技术进行老战士与历史场景还原&#xff0c;让抗美援朝老战士可以通过虚拟现实技术&#xff0c;跨越时空与战友实现隔空对话。 随着动捕设备的不断发展&#xff0c;虚拟现实技术越来越成熟&a…

WGS84地球坐标系,GCJ02火星坐标系,BD09百度坐标系简介与转换 资料收集

野火 ATGM332D简介 高性能、低功耗 GPS、北斗双模定位模块 STM32 GPS定位_为了维护世界和平_的博客-CSDN博客 秉火多功能调试助手上位机开源&#xff01;共六款软件&#xff0c;学到你吐... , - 电脑上位机 - 野火电子论坛 - Powered by Discuz! https://www.firebbs.cn/for…

M1 Pro 利用docker 搭建pytho2的开发环境,以vscode连接开发为例

使用 M1 Pro &#xff08;不支持python2的安装&#xff09;开发&#xff0c;需要使用 Python 2.7 的环境&#xff0c;在使用 pyenv 安装 Python 2 时遇到了各种奇怪的问题。最终&#xff0c;我决定使用 Docker 搭建开发环境&#xff0c;并使用 VS Code 连接到本地容器。以下是详…

Unity 应用消息中心-MessageCenter

Ps&#xff1a;主要解决耦合问题&#xff0c;把脚本之间的联系通过不同消息类型事件形式进行贯通 1.MessageCenter主脚本 2.DelegateEvent消息类型脚本 3.MC_Default_Data具体接收类脚本 using System; using System.Collections; using System.Collections.Generic; using …

unity 模型显示在UI上 并交互(点击、旋转、缩放)

项目工程&#xff1a;unity模型显示在UI上并交互&#xff08;点击、旋转、缩放&#xff09;资源-CSDN文库 1.在Assets创建 Render Texture&#xff08;下面会用到&#xff09;&#xff0c;根据需要设置Size 2.创建UIRawImage&#xff0c;并把Render Texture赋上 3.创建相机&am…

Docker安装并配置Pushgateway

Linux下安装Docker请参考&#xff1a;Linux安装Docker 简介 Pushgateway是Prometheus的一个组件&#xff0c;prometheus server默认是通过Exporter主动获取数据&#xff08;默认采取pull拉取数据&#xff09;&#xff0c;Pushgateway则是通过exporter主动方式推送数据到Pushg…

前端需要理解的CSS知识

CSS&#xff08;层叠样式表&#xff0c;Cascading Style Sheets&#xff09;不是编程语言&#xff0c;而是用来描述 HTML 或 XML&#xff08;包括如 SVG、MathML 或 XHTML 之类的 XML 分支语言&#xff09;文档的表现与展示效果的样式表语言。CSS3是CSS的最新标准&#xff0c;是…

mysql基础——认识索引

一、介绍 “索引”是为了能够更快地查询数据。比如一本书的目录&#xff0c;就是这本书的内容的索引&#xff0c;读者可以通过在目录中快速查找自己想要的内容&#xff0c;然后根据页码去找到具体的章节。 二、优缺点 优势&#xff1a;以快速检索&#xff0c;减少I/O次数&am…

【Go语言】基于Socket编程的P2P通信程序示例

Go语言的Socket编程实现为开发者提供了一种高效且强大的方式来实现网络通信。通过Go语言的并发模型和内置的网络库&#xff0c;如net包&#xff0c;开发者可以轻松地创建基于套接字的通信应用。Go语言的goroutine和channel机制使并发处理变得简单&#xff0c;能够轻松处理多个连…

U盘怎么加密?U盘加密方法有哪些?

U盘是我们生活和工作中最常用的移动储存设备&#xff0c;经常被用来存放各种重要数据&#xff0c;为了保证数据的安全&#xff0c;我们需要加密U盘。那么&#xff0c;U盘加密方法有哪些呢&#xff1f; U盘加密普通方法 如果你的U盘储存数据不多&#xff0c;并且对于加密的要求…

Linux 系统下 GDB 调试器的使用

文章目录 简介GDB 的介绍GDB 的使用 GDB 常用命令及示例查看相关操作断点相关操作运行相关操作变量相关操作分隔窗口操作 简介 GDB 的介绍 GDB 是 GNU 调试程序&#xff0c;是用来调试 C 和 C 程序的调试器。它可以让程序开发者在程序运行时观察程序的内部结构和内存的使用情况…

初阶c语言:趣味扫雷游戏

目录 前言 制作菜单 构建游戏选择框架 实现游戏功能 模块化编程&#xff1a;查看前节三子棋的内容 初始化雷区 ​编辑 优化棋盘 随机埋入地雷 点击后的决策 实现此功能代码 game&#xff08;&#xff09;&#xff1b;的安排 前言 《扫雷》是一款大众类的益智小游戏&…

java八股文面试[JVM]——元空间

JAVA8为什么要增加元空间 为什么要移除永久代&#xff1f; 知识来源&#xff1a; 【2023年面试】JVM8为什么要增加元空间_哔哩哔哩_bilibili

Django 简易PACS读片系统

1、Django中写一个后端接口&#xff0c;给HTML提供dicom文件接口的方式 1、首先创建django项目 1、下载安装跨域的包 pip3 install django-cors-headers2、使用pycharm创建一个Django项目 3、点击创建在另一个窗口&#xff0c;这个都无所谓&#xff0c;怎么都行&#xff0c;…

Hadoop Yarn 配置多队列的容量调度器

文章目录 配置多队列的容量调度器多队列查看 配置多队列的容量调度器 首先&#xff0c;我们进入 Hadoop 的配置文件目录中&#xff08;$HADOOP_HOME/etc/hadoop&#xff09;&#xff1b; 然后通过编辑容量调度器配置文件 capacity-scheduler.xml 来配置多队列的形式。 默认只…