Linux信号基础(5)——实时信号

实时信号

        如果进程当前正在执行信号处理函数,在处理信号期间接收到了新的信号,如果该信号是信号掩码中的成员,那么内核会将其阻塞,将该信号添加到进程的等待信号集(等待被处理/处于等待状态的信号)中, 为了确定进程中处于等待状态的信号,可以使用 sigpending()函数获取。

sigpending()函数

        其函数原型如下所示:

#include <signal.h>

int sigpending(sigset_t *set);

        函数参数和返回值含义如下:

        set:处于等待状态的信号会存放在参数 set 所指向的信号集中。

        返回值:成功返回 0;失败将返回-1,并设置 errno。

使用示例        

/* 定义信号集 */
sigset_t sig_set;

/* 将信号集初始化为空 */
sigemptyset(&sig_set);

/* 获取当前处于等待状态的信号 */
sigpending(&sig_set);

/* 判断 SIGINT 信号是否处于等待状态 */
if (1 == sigismember(&sig_set, SIGINT))
    puts("SIGINT 信号处于等待状态");
else if (!sigismember(&sig_set, SIGINT))
    puts("SIGINT 信号未处于等待状态")

发送实时信号

        等待信号集只是一个掩码,仅表明一个信号是否发生,而不能表示其发生的次数。换言之,如果一个同一个信号在阻塞状态下产生了多次,那么会将该信号记录在等待信号集中,并在之后仅传递一次(仅当做发生了一次),这是标准信号的缺点之一。

        实时信号较之于标准信号,其优势如下:

        实时信号的信号范围有所扩大,可应用于应用程序自定义的目的,而标准信号仅提供了两个信号可用于应用程序自定义使用:SIGUSR1 和 SIGUSR2。
        内核对于实时信号所采取的是队列化管理。如果将某一实时信号多次发送给另一个进程,那么将会 多次传递此信号。相反,对于某一标准信号正在等待某一进程,而此时即使再次向该进程发送此信 号,信号也只会传递一次。
        当发送一个实时信号时,可为信号指定伴随数据(一整形数据或者指针值),供接收信号的进程在它的信号处理函数中获取。
        不同实时信号的传递顺序得到保障。如果有多个不同的实时信号处于等待状态,那么将率先传递具有最小编号的信号。换言之,信号的编号越小,其优先级越高,如果是同一类型的多个信号在排队, 那么信号(以及伴随数据)的传递顺序与信号发送来时的顺序保持一致。

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

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

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

        2、接收实时信号的进程要为该信号建立一个信号处理函数,使用sigaction函数为信号建立处理函数, 并加入 SA_SIGINFO,这样信号处理函数才能接收到实时信号及伴随数据,也就是要使用 sa_sigaction 指针指向的处理函数,如果使用 sa_handler则不能获取到实时信号的伴随数据。

        使用 sigqueue()函数发送实时信号,其函数原型如下所示:

#include <signal.h>

int sigqueue(pid_t pid, int sig, const union sigval value);

函数参数和返回值含义如下:

pid:指定接收信号的进程对应的 pid,将信号发送给该进程。

sig:指定需要发送的信号。与 kill()函数一样,也可将参数 sig 设置为 0,用于检查参数 pid 所指定的进 程是否存在。

value:参数 value 指定了信号的伴随数据,union sigval 数据类型。

返回值:成功将返回 0;失败将返回-1,并设置 errno。

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

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

携带的伴随数据,既可以指定一个整形的数据,也可以指定一个指针。

使用示例

(1)发送进程使用 sigqueue()系统调用向另一个进程发送实时信号

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

int main(int argc, char *argv[]){
     union sigval sig_val;
     int pid;
     int sig;
 
     /* 判断传参个数 */
     if (3 > argc)
         exit(-1);

     /* 获取用户传递的参数 */
     pid = atoi(argv[1]);
     sig = atoi(argv[2]);
     printf("pid: %d\nsignal: %d\n", pid, sig);
 
     /* 发送信号 */
     sig_val.sival_int = 10; //伴随数据
     if (-1 == sigqueue(pid, sig, sig_val)) {
         perror("sigqueue error");
     exit(-1);
     }
 
     puts("信号发送成功!");
     exit(0);
}

(2)接收进程使用 sigaction()函数为信号绑定处理函数

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

static void sig_handler(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);
}

int main(int argc, char *argv[]){
     struct sigaction sig = {0};
     int num;
 
     /* 判断传参个数 */
     if (2 > argc)
         exit(-1);
 
     /* 获取用户传递的参数 */
     num = atoi(argv[1]);
 
     /* 为实时信号绑定处理函数 */
     sig.sa_sigaction = sig_handler;
     sig.sa_flags = SA_SIGINFO;
     if (-1 == sigaction(num, &sig, NULL)) {
         perror("sigaction error");
     exit(-1);
     }
 
     /* 死循环 */
     for ( ; ; )
         sleep(1);
     exit(0);
}

关于Linux信号的学习告一段落,接下来学习进程的知识。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值