Linux实时信号不会丢失

Linux中的 实时信号 (又称为 可靠信号 )在被阻塞的时候,不会像 非实时信号 不可靠信号 )那样丢失。

因为 非实时信号的等待信号集是以集合的数据结构进行管理的 ,所谓集合有一个重要的性质就是元素不能够重复,而 实时信号是以队列的形式来管理等待信号的,所以不会存在信号丢失的问题

对于 非实时信号 ,当进程的信号掩码中存在某个非实时信号,那么当这个非实时信号发送给进程的时候,会被内核阻塞,内核会将其放在一个叫做等待信号集的数据结构里面,只有此信号从进程的信号掩码中移除之后,内核才会把等待信号集中的该信号发送给进程,如果在信号阻塞期间,又发送来了相同的信号,那么由于集合的元素不可重复,所以这个重复发送的信号将会被内核丢弃,称为信号丢失,当解除阻塞之后,仅仅会响应一次被阻塞的信号处理函数

对于实时信号而言,由于等待信号(即被内核阻塞期间又发送同样的信号)采用队列管理,所以不存在信号丢失的情况发生,如果某个信号在阻塞期间又多次发送,那么内核会记录信号发送的次数。也就是说:实时信号是可以在阻塞期间重复发送,而不会丢失的,当解除阻塞之后,会多次响应实时信号的信号处理函数!

怎么验证实时信号不可以被阻塞呢?

当然是实践出真知喽:下面通过代码来实践一下:

程序1:阻塞接收来此其他进程发送的实时信号

/**
  ****************************************************************************************
  * @file    09_sigaction.c
  * @author  GuiStar-李什么恩
  * @version V1.1.0
  * @date    2023-4-14
  * @brief   挂起进程,阻塞参数1指定的实时信号,当接收到SIGINT信号之后,进程会被唤醒
  *          并取消对参数1指定的实时信号的阻塞(即从信号掩码中移除),此程序用来验证实
  *          时信号不会丢失
  ****************************************************************************************
  */
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

static void sig_handler1(int sig)
{
    printf("接收到SIGINT,即将唤醒程序!\n");
}

static void sig_handler2(int sig, siginfo_t *info, void *context)
{
    sigval_t sig_val = info->si_value;
    printf("接收到实时信号: %d\n", sig);
    printf("伴随数据为: %d\n", sig_val.sival_int);
    printf("发送方的PID是:%d\n",info->si_pid);
}

int main(int argc, char *argv[])
{
    struct sigaction sig = {0};
    sigset_t sig_set;
    int num;

    /* 判断传参个数 */
    if (argc<2)
    {
        printf("参数过少\n");
        exit(-1);
    }
    /* 获取用户传递的参数 */
    num = atoi(argv[1]);

    sigemptyset(&sig_set);
    sigaddset(&sig_set, num);

    /* 为实时信号绑定处理函数 */
    sig.sa_handler = sig_handler1;
    sig.sa_flags = 0;
    if (sigaction(SIGINT, &sig, NULL)==-1)
    {
        perror("sigaction error");
        exit(-1);
    }
    sig.sa_sigaction = sig_handler2;
    sig.sa_flags = SA_SIGINFO;
    if (sigaction(num, &sig, NULL)==-1)
    {
        perror("sigaction error");
        exit(-1);
    }
    
    /*挂起此进程,等待SIGINT信号来唤醒,同时阻塞用户给此进程参数指定的实时信号*/
    printf("开始挂起进程,同时阻塞%d信号\n",num);
    if (sigsuspend(&sig_set)!=-1)
    exit(-1);

    printf("程序唤醒成功!\n");


    exit(0);
}



程序2:向某个进程发送实时信号:

/**
  ****************************************************************************************
  * @file    09_sigqueue.c
  * @author  GuiStar-李什么恩
  * @version V1.1.0
  * @date    2023-4-14
  * @brief   向某个进程发送实时信号,参数1指定接受进程的pid号,参数2指定要发送的实时信号的编号
  ****************************************************************************************
  */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main(int argc, char *argv[])
{
    union sigval sig_val;
    int pid;
    int sig;
    /* 判断传参个数 */
    if (argc<3)
    {
        puts("参数过少,参数一:pid,参数二:实时信号");
        exit(-1);
    }

    /* 获取用户传递的参数 */
    pid = atoi(argv[1]);
    sig = atoi(argv[2]);
    printf("pid: %d\nsignal: %d\n", pid, sig);

    /* 发送信号 */
    sig_val.sival_int = 10; //伴随数据
    if (sigqueue(pid, sig, sig_val)==-1) 
    {
        perror("sigqueue error");
        exit(-1);
    }
    puts("信号发送成功!");
    exit(0);
}

运行结果:

  • 首先运行程序1,程序首先会挂起,会阻塞指定的实时信号34,如果按下ctrl+c,发送SIGINT信号,则程序会被唤醒,同时解除对实时信号34的阻塞
    在这里插入图片描述

  • 然后,在查询到程序1的pid之后,多次运行程序2,向程序1的进程多次发送实时信号34。此时进程1是被挂起的,并且实时信号34被内核阻塞,所以在进程1的终端看不到响应信息。只有取消阻塞,进程1才会响应这些实时信号34

在这里插入图片描述


  • 按下ctrl+c,发送SIGINT信号,进程1被唤醒从下图中可以看出,进程1确实多次响应了在阻塞期间发送的实时信号34

在这里插入图片描述


至此实时信号不会被丢弃得到验证!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuiStar_李什么恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值