热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

实时信号与sigqueue函数

一、sigqueue函数功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。原型:intsigq

一、sigqueue函数

功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
原型:int sigqueue(pid_t pid, int sig, const union sigval value);
参数:
 sigqueue的第一个参数是指定接收信号的进程id,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。
返回值:成功返回0,失败返回-1 

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

 

sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。

写两个小程序测试一下:

首先是接收信号:

 

C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34@163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int, siginfo_t *, void *);


int main(int argc, char *argv[])
{
    struct sigaction act;
    act.sa_sigaction = handler; //sa_sigaction与sa_handler只能取其一
    //sa_sigaction多用于实时信号,可以保存信息
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO; // 设置标志位后可以接收其他进程
    // 发送的数据,保存在siginfo_t结构体中

    if (sigaction(SIGINT, &act, NULL) < 0)
        ERR_EXIT("sigaction error");

    for (; ;)
        pause();

    return 0;

}

void handler(int sig, siginfo_t *info, void *ctx)
{
    printf("recv a sig&#61;%d data&#61;%d data&#61;%d\n",
           sig, info->si_value.sival_int, info->si_int);

}

 

在前面的《信号捕捉与sigaction函数》中说过&#xff0c;sa_sigaction与SA_SIGINFO要配合使用&#xff0c;如上所示&#xff0c;siginfo_t 结构体也可以参见这篇文章。

 

然后是信号发送&#xff1a;

 

C&#43;&#43; Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
/*************************************************************************
    > File Name: process_.c
    > Author: Simba
    > Mail: dameng34&#64;163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)



int main(int argc, char *argv[])
{
    if (argc !&#61; 2)
    {
        fprintf(stderr, "Usage %s pid\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    pid_t pid &#61; atoi(argv[1]); //字符串转换为整数
    union sigval val;
    val.sival_int &#61; 100;
    sigqueue(pid, SIGINT, val); // 只可以发信号给某个进程&#xff0c;而不能是进程组

    return 0;

}

 

测试如下&#xff1a;

先运行recv程序&#xff1a;

simba&#64;ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigqueue_recv 

再ps出recv进程的pid&#xff0c;然后运行send程序&#xff1a;

simba&#64;ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigqueue_send 3323

则recv进程会输出一条recv语句&#xff0c;当然我们也可以ctrl&#43;c 给自己发送信号&#xff0c;如下所示&#xff0c;结果是一样的。

recv a sig&#61;2 data&#61;100 data&#61;100
^Crecv a sig&#61;2 data&#61;100 data&#61;100
^Crecv a sig&#61;2 data&#61;100 data&#61;100

......................................................

需要提醒一下的是siginfo_t 结构体的两个参数&#xff08;int  si_int;   /* POSIX.1b signal */     void  *si_ptr;  /* POSIX.1b signal */&#xff09;的值也会与si_value 一致&#xff0c;取决于发送的是sival_int 还是 sival_ptr。

 

二、实时信号与不可靠信号的区别

下面通过程序来说明区别&#xff0c;主要就是实时信号支持排队不会丢失。&#xff08;实时信号还有一个特点&#xff0c;即到达的顺序是可以保证的&#xff09;

先是recv程序&#xff1a;

 

C&#43;&#43; Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 


#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int);

int main(int argc, char *argv[])
{
    struct sigaction act;
    act.sa_handler &#61; handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags &#61; 0;

    sigset_t s;
    sigemptyset(&s);
    sigaddset(&s, SIGINT);
    sigaddset(&s, SIGRTMIN);
    sigprocmask(SIG_BLOCK, &s, NULL);
    if (sigaction(SIGINT, &act, NULL) < 0)
        ERR_EXIT("sigaction error");

    if (sigaction(SIGRTMIN, &act, NULL) < 0)
        ERR_EXIT("sigaction error");

    if (sigaction(SIGUSR1, &act, NULL) < 0)
        ERR_EXIT("sigaction error");
    for (;;)
        pause();
    return 0;
}

void handler(int sig)
{
    if (sig &#61;&#61; SIGINT || sig &#61;&#61; SIGRTMIN)
        printf("recv a sig&#61;%d\n", sig);
    else if (sig &#61;&#61; SIGUSR1)
    {
        sigset_t s;
        sigemptyset(&s);
        sigaddset(&s, SIGINT);
        sigaddset(&s, SIGRTMIN);
        sigprocmask(SIG_UNBLOCK, &s, NULL);
    }
}

 

在主函数中将SIGINT和SIGRTMIN信号加入信号屏蔽字&#xff0c;只有当接收到SIGUSR1信号时才对前面两个信号unblock。需要注意的是如《信号的未决与阻塞》中说的一样&#xff1a;如果在信号处理函数中对某个信号进行解除阻塞时&#xff0c;则只是将pending位清0&#xff0c;让此信号递达一次&#xff08;同个实时信号产生多次进行排队都会抵达&#xff09;&#xff0c;但不会将block位清0&#xff0c;即再次产生此信号时还是会被阻塞&#xff0c;处于未决状态。

 

接着是send程序&#xff1a;

 

C&#43;&#43; Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
/*************************************************************************
    > File Name: sigrtime_send.c
    > Author: Simba
    > Mail: dameng34&#64;163.com
    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
 ************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)



int main(int argc, char *argv[])
{
    if (argc !&#61; 2)
    {
        fprintf(stderr, "Usage %s pid\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    pid_t pid &#61; atoi(argv[1]); //字符串转换为整数
    union sigval val;
    val.sival_int &#61; 100;
    sigqueue(pid, SIGINT, val); // 不可靠信号不会排队&#xff0c;即会丢失
    sigqueue(pid, SIGINT, val);
    sigqueue(pid, SIGINT, val);
    sigqueue(pid, SIGRTMIN, val); //实时信号会排队&#xff0c;即不会丢失
    sigqueue(pid, SIGRTMIN, val);
    sigqueue(pid, SIGRTMIN, val);
    sleep(3);
    kill(pid, SIGUSR1);

    return 0;

}

 

先是运行recv程序&#xff1a;

simba&#64;ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigrtime_recv2

接着ps出recv进程的pid&#xff0c;运行send程序&#xff1a;

simba&#64;ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigrtime_send 4076

在send程序中连续各发送了SIGINT和SIGRTMIN信号3次&#xff0c;接着睡眠3s后使用kill函数发送SIGUSR1信号给recv进程&#xff0c;此时recv进程会输出如下&#xff1a;

recv a sig&#61;34
recv a sig&#61;34
recv a sig&#61;34
recv a sig&#61;2

即实时信号支持排队&#xff0c;3个信号都接收到了&#xff0c;而不可靠信号不支持排队&#xff0c;只保留一个信号。

 

参考&#xff1a;《APUE》



推荐阅读
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • HNOI2003 激光炸弹问题(二维前缀和的应用)难度:中等
    HNOI2003 激光炸弹问题是一个经典的二维前缀和应用题目。本文将详细介绍如何使用二维前缀和解决该问题。 ... [详细]
  • 题目编号:2049 [SDOI2008]Cave Exploration。题目描述了一种动态图操作场景,涉及三种基本操作:断开两个节点间的连接(destroy(a,b))、建立两个节点间的连接(connect(a,b))以及查询两节点是否连通(query(a,b))。所有操作均确保图中无环存在。 ... [详细]
  • 题目描述:计算从起点到终点的最小能量消耗。如果下一个单元格的风向与当前单元格相同,则消耗为0,否则为1。共有8个可能的方向。 ... [详细]
  • 探讨了一个包含纯虚函数的C++代码片段,分析了其中的语法错误及逻辑问题,并提出了修正方案。 ... [详细]
  • 想把一组chara[4096]的数组拷贝到shortb[6][256]中,尝试过用循环移位的方式,还用中间变量shortc[2048]的方式。得出的结论:1.移位方式效率最低2. ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 本问题涉及在给定的无向图中寻找一个至少包含三个节点的环,该环上的节点不重复,并且环上所有边的长度之和最小。目标是找到并输出这个最小环的具体方案。 ... [详细]
  • 高级缩放示例.就像谷歌地图一样.它仅缩放图块,但不缩放整个图像.因此,缩放的瓷砖占据了恒定的记忆,并且不会为大型缩放图像调整大小的图像.对于简化的缩放示例lookhere.在Win ... [详细]
  • linux网络子系统分析(二)—— 协议栈分层框架的建立
    目录一、综述二、INET的初始化2.1INET接口注册2.2抽象实体的建立2.3代码细节分析2.3.1socket参数三、其他协议3.1PF_PACKET3.2P ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
  • 深入理解线程池及其基本实现
    本文探讨了线程池的概念、优势及其在Java中的应用。通过实例分析不同类型的线程池,并指导如何构建一个简易的线程池。 ... [详细]
  • 本文详细介绍了在Luat OS中如何实现C与Lua的混合编程,包括在C环境中运行Lua脚本、封装可被Lua调用的C语言库,以及C与Lua之间的数据交互方法。 ... [详细]
  • 函子(Functor)是函数式编程中的一个重要概念,它不仅是一个特殊的容器,还提供了一种优雅的方式来处理值和函数。本文将详细介绍函子的基本概念及其在函数式编程中的应用,包括如何通过函子控制副作用、处理异常以及进行异步操作。 ... [详细]
author-avatar
晦涩的爱情嵌
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有