嵌入式Linux系统编程 — 6.7 实时信号

目录

1 什么是实时信号

2 sigqueue函数

3 sigpending()函数


1 什么是实时信号

等待信号集只是一个掩码,它并不追踪信号的发生次数。这意味着,如果相同的信号在被阻塞的状态下多次产生,它只会在信号集中被记录一次,并且在信号集被检查时仅被视为一个事件。这是标准信号的缺点之一。

与标准信号不同,实时信号可以排队,如果同一个实时信号多次发送给同一个进程,它们将被排队处理,而不是像标准信号那样只能触发一次。实时信号较之于标准信号,其优势如下:

  • 可排队: 实时信号可以排队等待处理,如果一个信号多次到达,它只会被处理一次,除非它被显式地从队列中移除并重新发送。
  • 优先级队列: 实时信号具有与信号相关联的默认实时优先级。如果一个实时信号被发送,它将按照其优先级顺序处理,这有助于确保高优先级的信号能够及时被处理。

  • 应用定义的处理: 实时信号可以有应用程序定义的处理函数,类似于传统信号,但是它们可以安全地使用在多线程环境中。

  • 不干扰传统信号: 实时信号与标准信号(如 SIGKILLSIGSTOP)分开处理,因此不会受到这些信号的影响。

Linux 内核定义了 31 个不同的实时信号,信号编号范围为 34~64,使用 SIGRTMIN 表示编号最小的实时信号,使用 SIGRTMAX 表示编号最大的实时信号,其它信号编号可使用这两个宏加上一个整数或减去一个整数。

应用程序当中使用实时信号,需要有以下的两点要求:

  • 发送进程使用 sigqueue()系统调用向另一个进程发送实时信号以及伴随数据。

  • 接收实时信号的进程要为该信号建立一个信号处理函数,使用sigaction函数为信号建立处理函数,并加入 SA_SIGINFO,这样信号处理函数才能够接收到实时信号以及伴随数据,也就是要使用sa_sigaction 指针指向的处理函数,而不是 sa_handler,当然允许应用程序使用 sa_handler,但这样就不能获取到实时信号的伴随数据了。

2 sigqueue函数

sigqueue() 函数是用于发送实时信号给指定进程的 POSIX 函数。实时信号是 POSIX 1003.1b 标准的一部分,它们允许发送者指定信号的属性,如信号值和与之关联的数据。函数原型如下:

#include <signal.h>

int sigqueue(pid_t pid, int sig, const union sigval value);
  • pid:接收信号的进程的进程 ID。如果 pid 为负值,信号将发送给指定会话中的所有进程。
  • signum:要发送的信号的编号。它应该是 SIGRTMIN 到 SIGRTMAX 之间的值,表示一个实时信号。
  • value:参数 value 指定了信号的伴随数据, union sigval 数据类型。
  • 返回值:成功时返回 0,失败时返回 -1,并设置 errno 以指示错误。

union sigval 数据类型(共用体) 如下所示:

typedef union sigval
{
    int sival_int;
    void *sival_ptr;
} sigval_t;

下面的示例代码是一个基本的父子进程通信程序,其中父进程使用 sigqueue 函数向子进程发送一个信号和附加数据。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() 
{
    pid_t pid = fork(); // 创建子进程

    if (pid == -1) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        // 子进程
        printf("Child process is waiting for signal...\n");
        pause(); // 子进程挂起,等待信号
        exit(EXIT_FAILURE); // 确保子进程在接收信号前不会退出
    } else {
        // 父进程
        printf("Parent process is sending signal to child...\n");
        sleep(2); // 让子进程先打印等待信息

        // 声明sigval变量并初始化
        union sigval value;
        value.sival_ptr = "Hello from parent!"; // 设置信号值

        if (sigqueue(pid, SIGUSR1, value) == -1) {
            perror("sigqueue failed");
            exit(EXIT_FAILURE);
        }
        printf("Signal sent successfully.\n");

        int status;
        waitpid(pid, &status, 0); // 等待子进程结束
        if (WIFEXITED(status)) {
            printf("Child exited with status %d\n", WEXITSTATUS(status));
        }
    }

    return 0;
}

在这段代码中,父进程首先创建了一个子进程,然后子进程调用 pause 进入等待状态,直到接收到信号。父进程在稍作延时后使用 sigqueue 发送 SIGUSR1 信号给子进程,并附带一个 sigval 类型的联合体,其中 sival_ptr 成员指向一个字符串 "Hello from parent!"。如果 sigqueue 调用成功,父进程将打印一条成功消息,并等待子进程结束。父进程随后检查子进程的退出状态,并打印出来。

3 sigpending()函数

sigpending 函数用于查询系统中挂起(pending)的信号集,挂起的信号是指那些已经发送给进程,但尚未被进程处理的信号。函数原型如下:

#include <signal.h> 

int sigpending(set_t *set);
  • set_t:处于等待状态的信号会存放在参数 set 所指向的信号集中。

下面是一个简单的使用 sigpending 函数的示例:

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

int main() 
{
    sigset_t pending_set;

    // 检查错误
    if (sigpending(&pending_set) == -1) {
        perror("sigpending failed");
        return 1;
    }

    // 检查特定信号是否挂起
    if (sigismember(&pending_set, SIGINT)) {
        printf("SIGINT is pending.\n");
    } else {
        printf("SIGINT is not pending.\n");
    }

    return 0;
}

在这个示例中,程序首先调用 sigpending 来获取当前挂起的信号集,然后使用 sigismember 函数检查 SIGINT是否在挂起信号集中。如果 SIGINT 信号挂起,程序将打印相应的消息。如果 sigpending 调用失败,程序将打印错误信息并返回。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Django文档简化版——Django快速入门——创建一个基本的投票应用程序

Django快速入门——创建一个基本的投票应用程序 准备工作1、创建虚拟环境2、安装django 1、请求和响应&#xff08;1&#xff09;创建项目&#xff08;2&#xff09;用于开发的简易服务器&#xff08;3&#xff09;创建投票应用&#xff08;4&#xff09;编写第一个视图1、编写…

FreeRTOS的任务间通信

文章目录 4 FreeRTOS任务间通信4.1 队列4.1.1 队列的使用4.1.2 队列的创建&#xff0c;删除&#xff0c;复位4.1.3 队列的发送&#xff0c;接收&#xff0c;查询 4.2 邮箱&#xff08;mailbox&#xff09;4.2.1 任务中读写邮箱4.2.2 中断中读写邮箱 4.3 队列集4.3.1 队列集的创…

linux19:程序替换

一&#xff1a;最简单的看看程序替换是什么样的&#xff08;单个进程版&#xff09; 1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 int main()5 {6 printf("Before : I am a process , myPid:%d,myPPid:%d\n",getpid(),getpp…

【Ubuntu】详细说说Parallels DeskTop安装和使用Ubuntu系统

希望文章能给到你启发和灵感~ 如果觉得文章对你有帮助的话,点赞 + 关注+ 收藏 支持一下博主吧~ 阅读指南 开篇说明一、基础环境说明1.1 硬件环境1.2 软件环境二、Ubuntu系统的使用2.1 系统的下载2.2 系统的安装2.3 安装桌面版(可选)2.3.1 安装/更新apt2.3.2 安装桌面版2.3…

算法day02 回文 罗马数字转整数

回文 搞错了String类型的indexOf方法&#xff0c;理解成获取对应下标的值&#xff0c;实际上是在找对应值的下标。 4ms 耗时最少的方法尽量不会去调用jdk提供的方法&#xff0c;而是直接使用对应的数学逻辑关系来处理&#xff0c; 甚至用 代替equals方法。 罗马数字转整数 考…

Simulink中示波器连续运行的方法

1.在Simulink中,经常要使用到示波器,默认示波器是定时运行的,只能观察到一小部分运行的波形;实际调试过程中,经常要连续运行,因此,需要设置示波器为连续运行模式,下面将介绍示波器连续运行的方法。 打开Simulink仿真软件,找到仿真设置按钮,点击设置: 2.将其停止时间…

Oracle 解决4031错误

一、问题描述 什么是4031错误和4031错误产生的原因: 简单一个句话概括: 由于服务器一直在执行大量的硬解析,导致Oracle 的shared pool Free空间碎片过多,大的chunk不足, 当又一条复杂的sql语句要硬解析时, 缺少1个足够大的Free chunk, 通常就会报4031错误. 二、解决方法 临…

JVM原理(十五):JVM虚拟机静态分配与动态分配

1. 分派 本节讲解的分派调用过程将会揭示多态性特征的一-些最基本的体现&#xff0c;如“重载”和“重写”在Java虚拟机之中是如何实现的。 1.1. 静态分派 案例&#xff1a; 我们先来看一段代码: Human mannew Man(); 我们把上面代码中的“Human"称为变量的“静态类型…

9 redis,memcached,nginx网络组件

课程目标: 1.网络模块要处理哪些事情 2.reactor是怎么处理这些事情的 3.reactor怎么封装 4.网络模块与业务逻辑的关系 5.怎么优化reactor? io函数 函数调用 都有两个作用:io检测 是否就绪 io操作 1. int clientfd = accept(listenfd, &addr, &len); 检测 全连接队列…

Contact Form 7表单获取提交用户IP及URL等信息

有时候&#xff0c;您可能需要了解Contact Form 7表单提交后的更多的信息&#xff0c;而不仅仅是通过联系人表单字段获取用户的联系信息。例如&#xff0c;需要知道用户是哪个国家&#xff08;通过获取IP&#xff09;&#xff0c;了解用户使用的设备&#xff08;手机还是电脑&a…

【IDEA】maven如何进行文件导入,配置并打包

一&#xff0c;介绍、安装 1、maven介绍 maven是一个Java世界中&#xff0c;构建工具。 核心功能&#xff1a; (1) 管理依赖&#xff1a; 管理文件运行的顺序逻辑依赖关系。对配置文件&#xff0c;进行构建和编译。其也是在调用jdk&#xff0c;来进行编译打包工作。 (2) 打…

Protobuf(三):理论学习,简单总结

1. Protocol Buffers概述 Protocol Buffers&#xff08;简称protobuf&#xff09;&#xff0c;是谷歌用于序列化结构化数据的一种语言独立、平台独立且可扩展的机制&#xff0c;类似XML&#xff0c;但比XML更小、更快、更简单protobuf的工作流程如图所示 1.1 protobuf的优点…

2024上海初中生古诗文大会暑期备考:单选题真题示例和独家解析

现在距离2024年初中生古诗文大会初选还有不到4个月&#xff08;11月3日正式开赛&#xff09;&#xff0c;我们继续来看10道选择题真题和详细解析。为帮助孩子自测和练习&#xff0c;题目的答案和解析统一附后。 本专题持续分享。 一、上海初中古诗文大会历年真题精选(参考答案…

【ROS2】初级:CLI工具- 启动节点

目标&#xff1a;使用命令行工具一次启动多个节点。 教程级别&#xff1a;初学者 时间&#xff1a;5 分钟 目录 背景 先决条件 任务 运行启动文件控制 Turtlesim 节点&#xff08;可选&#xff09; 摘要 下一步 背景 在大多数入门教程中&#xff0c;您每运行一个新节点就会打开…

【Unity配置数据文件】ScriptableObject核心应用

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 专栏交流&#x1f9e7;&…

NASA——quarius(水瓶座) L3 网格化 1 度年土壤湿度,第 5 版

Aquarius L3 Gridded 1-Degree Annual Soil Moisture V005 水瓶座 L3 网格化 1 度年土壤湿度&#xff0c;第 5 版 简介 该数据集包含美国国家航空航天局&#xff08;NASA&#xff09;科学应用卫星&#xff08;SAC-D&#xff09;上的宝瓶座被动微波辐射计得出的第 3 级网格化…

前端面试题5(前端常见的加密方式)

前端常见的加密方式 在前端进行数据加密主要是为了保护用户的隐私和提升数据传输的安全性。前端数据加密可以采用多种方法&#xff0c;以下是一些常见的加密技术和方法&#xff1a; 1. HTTPS 虽然不是直接的前端加密技术&#xff0c;但HTTPS是保障前端与后端数据传输安全的基…

【BUUCTF-PWN】12-get_started_3dsctf_2016

32位&#xff0c;开启了NX保护 执行效果&#xff1a; main函数&#xff1a; 其中gets()函数存在栈溢出&#xff0c;溢出距离为0x38&#xff0c;这里是使用的esp寻址&#xff0c;属于外平栈&#xff0c;不需要覆盖ebp的四个字节。而之前做的题一般都是ebp寻址&#xff0c;…

Golang | Leetcode Golang题解之第216题组合总和III

题目&#xff1a; 题解&#xff1a; func combinationSum3(k int, n int) (ans [][]int) {var temp []intvar dfs func(cur, rest int)dfs func(cur, rest int) {// 找到一个答案if len(temp) k && rest 0 {ans append(ans, append([]int(nil), temp...))return}/…

【Python机器学习】模型评估与改进——二分类指标

目录 1、错误类型 2、不平衡数据集 3、混淆矩阵 与精度的关系。 准确率、召回率与f-分数 分类报告 4、考虑不确定性 5、准确率-召回率曲线 6、受试者工作特征&#xff08;ROC&#xff09;与AUC 二分类可能是实践中最常见的机器学习应用&#xff0c;也是概念最简单的应…