信号发送函数sigqueue和信号安装函数sigaction

sigaction函数用于改变进程接收到特定信号后的行为。

sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然也支持前32种),支持信号带有参数,与函数sigaction()配合使用。

sigqueue的第一个参数是指定接收信号的进程ID,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。

一,sigaction()

#include    int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

sigaction函数用于改变进程接收到特定信号后的行为。该函数的第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。

第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等。

sigaction结构定义如下:

struct sigaction {

union{

__sighandler_t _sa_handler;

void (*_sa_sigaction)(int,struct siginfo *, void *);

}_u

sigset_t sa_mask;

unsigned long sa_flags;

void (*sa_restorer)(void);

}

其中,sa_restorer,已过时,POSIX不支持它,不应再被使用。

1、联合数据结构中的两个元素_sa_handler以及*_sa_sigaction指定信号关联函数,即用户指定的信号处理函数。除了可以是用户自定义的处理函数外,还可以为SIG_DFL(采用缺省的处理方式),也可以为SIG_IGN(忽略信号)。

2、由_sa_handler指定的处理函数只有一个参数,即信号值,所以信号不能传递除信号值之外的任何信息;由_sa_sigaction是指定的信号处理函数带有三个参数,是为实时信号而设的(当然同样支持非实时信号),它指定一个3参数信号处理函数。第一个参数为信号值,第三个参数没有使用(posix没有规范使用该参数的标准),第二个参数是指向siginfo_t结构的指针,结构中包含信号携带的数据值,参数所指向的结构如下:

typedef struct siginfo_t{

int si_signo;//信号编号

int si_errno;//如果为非零值则错误代码与之关联

int si_code;//说明进程如何接收信号以及从何处收到

pid_t si_pid;//适用于SIGCHLD,代表被终止进程的PID

pid_t si_uid;//适用于SIGCHLD,代表被终止进程所拥有进程的UID

int si_status;//适用于SIGCHLD,代表被终止进程的状态

clock_t si_utime;//适用于SIGCHLD,代表被终止进程所消耗的用户时间

clock_t si_stime;//适用于SIGCHLD,代表被终止进程所消耗系统的时间

sigval_t si_value;

int si_int;

void * si_ptr;

void* si_addr;

int si_band;

int si_fd;

};

siginfo_t结构中的联合数据成员确保该结构适应所有的信号,比如对于实时信号来说,则实际采用下面的结构形式:

typedef struct {

int si_signo;

int si_errno;

int si_code;

union sigval si_value;

} siginfo

结构的第四个域同样为一个联合数据结构:

union sigval {

int sival_int;

void *sival_ptr;

}

采用联合数据结构,说明siginfo_t结构中的si_value要么持有一个4字节的整数值,要么持有一个指针,这就构成了与信号相关的数据。在信号的处理函数中,包含这样的信号相关数据指针,但没有规定具体如何对这些数据进行操作,操作方法应该由程序开发人员根据具体任务事先约定。

sigval结构体:系统调用sigqueue发送信号时,sigqueue的第三个参数就是sigval联合数据结构,当调用sigqueue时,该数据结构中的数据就将拷贝到信号处理函数的第二个参数中。这样,在发送信号同时,就可以让信号传递一些附加信息。信号可以传递信息对程序开发是非常有意义的。

siginfo_t.si_value与sigqueue(pid_t pid, int sig, const union sigval val)第三个参数关联即:

所以通过siginfo_t.si_value可以获得sigqueue(pid_t pid, int sig, const union sigval val)第三个参数传递过来的数据。

如:siginfo_t.si_value.sival_int或siginfo_t.si_value.sival_ptr

其实siginfo_t.si_int直接与sigval.sival_int关联

siginfo_t.si_ptr直接与sigval.sival_ptr关联,所以也可同这种方式获得sigqueue发送过来的数据。

信号参数的传递过程可图示如下:

3、sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下当前信号本身被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位,处理程序执行完后,被阻塞的信号开始执行。

注:请注意sa_mask指定的信号阻塞的前提条件,是在由sigaction()安装信号的处理函数执行过程中由sa_mask指定的信号才被阻塞。

4、sa_flags中包含了许多标志位,包括刚刚提到的SA_NODEFER及SA_NOMASK标志位。另一个比较重要的标志位是SA_SIGINFO,当设定了该标志位时,表示信号附带的参数可以被传递到信号处理函数中,因此,应该为sigaction结构中的sa_sigaction指定处理函数,而不应该为sa_handler指定信号处理函数,否则,设置该标志变得毫无意义。即使为sa_sigaction指定了信号处理函数,如果不设置SA_SIGINFO,信号处理函数同样不能得到信号传递过来的数据,在信号处理函数中对这些信息的访问都将导致段错误(Segmentation fault)。

注:很多文献在阐述该标志位时都认为,如果设置了该标志位,就必须定义三参数信号处理函数。实际不是这样的,验证方法很简单:自己实现一个单一参数信号处理函数,并在程序中设置该标志位,可以察看程序的运行结果。实际上,可以把该标志位看成信号是否传递参数的开关,如果设置该位,则传递参数;否则,不传递参数。

二,sigqueue()

之前学过kill,raise,alarm,abort等功能稍简单的信号发送函数,现在我们学习一种新的功能比较强大的信号发送函数sigqueue.

#include

#include

int sigqueue(pid_t pid, int sig, const union sigval val)

调用成功返回 0;否则,返回 -1。

sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然也支持前32种),支持信号带有参数,与函数sigaction()配合使用。

sigqueue的第一个参数是指定接收信号的进程ID,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。

typedef union sigval {

int  sival_int;

void *sival_ptr;

}sigval_t;

sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。如果signo=0,将会执行错误检查,但实际上不发送任何信号,0值信号可用于检查pid的有效性以及当前进程是否有权限向目标进程发送信号。

在调用sigqueue时,sigval_t指定的信息会拷贝到对应sig 注册的3参数信号处理函数的siginfo_t结构中,这样信号处理函数就可以处理这些信息了。由于sigqueue系统调用支持发送带参数信号,所以比kill()系统调用的功能要灵活和强大得多。

三,sigqueue与sigaction应用实例

实例一:利用sigaction安装SIGINT信号

#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 sig);

int main(int argc, char *argv[])

{

struct sigaction act;

act.sa_handler = handler;

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

//因为不关心SIGINT上一次的struct sigaction所以,oact为NULL

//与signal(handler,SIGINT)相同

if (sigaction(SIGINT, &act, NULL) < 0)

ERR_EXIT("sigaction error\n");

for (;;)

pause();

return 0;

}

void handler(int sig)

{

printf("recv a sig=%d\n", sig);

}

结果:

实例二:利用sigaction实现signal,实际上signal底层实现就是利用sigaction

#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 sig);

__sighandler_t my_signal(int sig, __sighandler_t handler);

int main(int argc, char *argv[])

{

my_signal(SIGINT, handler);

for (;;)

pause();

return 0;

}

__sighandler_t my_signal(int sig, __sighandler_t handler)

{

struct sigaction act;

struct sigaction oldact;

act.sa_handler = handler;

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

if (sigaction(sig, &act, &oldact) < 0)

return SIG_ERR;

return oldact.sa_handler;

}

void handler(int sig)

{

printf("recv a sig=%d\n", sig);

}

结果:

可知my_signal与系统调用signal具有相同的效果

实例三:验证sigaction.sa_mask效果

#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 sig);

int main(int argc, char *argv[])

{

struct sigaction act;

act.sa_handler = handler;

sigemptyset(&act.sa_mask);

sigaddset(&act.sa_mask, SIGQUIT);

act.sa_flags = 0;

if (sigaction(SIGINT, &act, NULL) < 0)

ERR_EXIT("sigaction error");

struct sigaction act2;

act2.sa_handler = handler;

sigemptyset(&act2.sa_mask);

act2.sa_flags = 0;

if (sigaction(SIGQUIT, &act2, NULL) < 0)

ERR_EXIT("sigaction error");

for (;;)

pause();

return 0;

}

void handler(int sig)

{

if(sig == SIGINT){

printf("recv a SIGINT signal\n");

sleep(5);

}

if (sig == SIGQUIT)

{

printf("recv a SIGQUIT signal\n");

}

}

结果:

可知,安装信号SIGINT时,将SIGQUIT加入到sa_mask阻塞集中,则当SIGINT信号正在执行处理函数时,SIGQUIT信号将被阻塞,只有当SIGINT信号处理函数执行完后才解除对SIGQUIT信号的阻塞,由于SIGQUIT是不可靠信号,不支持排队,所以只递达一次

示例四:给自身发送int型数据

#include

#include

#include

#include

void sighandler(int signo, siginfo_t *info,void *ctx);

//给自身传递信息

int main(void)

{

struct sigaction act;

act.sa_sigaction = sighandler;

sigemptyset(&act.sa_mask);

act.sa_flags = SA_SIGINFO;//信息传递开关

if(sigaction(SIGINT,&act,NULL) == -1){

perror("sigaction error");

exit(EXIT_FAILURE);

}

sleep(2);

union sigval mysigval;

mysigval.sival_int = 100;

if(sigqueue(getpid(),SIGINT,mysigval) == -1){

perror("sigqueue error");

exit(EXIT_FAILURE);

}

return 0;

}

void sighandler(int signo, siginfo_t *info,void *ctx)

{

//以下两种方式都能获得sigqueue发来的数据

printf("receive the data from siqueue by info->si_int is %d\n",info->si_int);

printf("receive the data from siqueue by info->si_value.sival_int is %d\n",info->si_value.sival_int);

}

结果:

示例五:进程间传递数据

接收端:

#include

#include

#include

#include

void sighandler(int signo, siginfo_t *info,void *ctx);

//给自身传递信息

int main(void)

{

struct sigaction act;

act.sa_sigaction = sighandler;

sigemptyset(&act.sa_mask);

act.sa_flags = SA_SIGINFO;//信息传递开关

if(sigaction(SIGINT,&act,NULL) == -1){

perror("sigaction error");

exit(EXIT_FAILURE);

}

for(; ;){

printf("waiting a SIGINT signal....\n");

pause();

}

return 0;

}

void sighandler(int signo, siginfo_t *info,void *ctx)

{

//以下两种方式都能获得sigqueue发来的数据

printf("receive the data from siqueue by info->si_int is %d\n",info->si_int);

printf("receive the data from siqueue by info->si_value.sival_int is %d\n",info->si_value.sival_int);

}

发送端:

#include

#include

#include

#include

int main(int argc, char **argv)

{

if(argc != 2){

fprintf(stderr,"usage:%s pid\n",argv[0]);

exit(EXIT_FAILURE);

}

pid_t pid = atoi(argv[1]);

sleep(2);

union sigval mysigval;

mysigval.sival_int = 100;

printf("sending SIGINT signal to %d......\n",pid);

if(sigqueue(pid,SIGINT,mysigval) == -1){

perror("sigqueue error");

exit(EXIT_FAILURE);

}

return 0;

}

结果:

由图可知接收成功

linux系统编程之文件与IO(七):时间函数小结

从系统时钟获取时间方式 time函数介绍: 1.函数名称: localtime 2.函数名称: asctime 3.函数名称: ctime 4.函数名称: difftime 5.函数名称: gmtim ...

Linux系统编程(9)—— 进程之进程控制函数exec系列函数

在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是: #include extern char **environ; int exe ...

Linux系统编程-setitimer函数

功能:linux系统编程中,setitimer是一个经常被使用的函数,可用来实现延时和定时的功能. 头文件:sys/time.h 函数原型: int setitimer(int which, cons ...

Linux系统编程(20)——信号基本概念

信号及信号来源 信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知 ...

linux系统编程之信号(一):中断与信号

一,什么是中断? 1.中断的基本概念 中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后又返回原来被 ...

linux系统编程之信号&lpar;七&rpar;

今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...

LINUX系统编程 由REDIS的持久化机制联想到的子进程退出的相关问题

19:22:01 2014-08-27 引言: 以前对wait waitpid 以及exit这几个函数只是大致上了解,但是看REDIS的AOF和RDB 2种持久化时 均要处理子进程运行完成退出和父进程 ...

Linux系统编程&commat;进程通信(一)

进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...

Linux 系统编程

简介和主要概念 Linux 系统编程最突出的特点是要求系统程序员对它们工作的的系统的硬件和操作系统有深入和全面的了解,当然它们还有库和系统调用上的区别. 系统编程分为:驱动编程.用户空间编程和网络编程 ...

随机推荐

《ASP&period;NET MVC 5框架揭秘》样章发布

今天算是新作正式上架销售的日子(目前本书在互动网已经到货),为了让更多适合的朋友们能够阅读此书,同时也避免让不适合的读者误买此书,特将此书的样章发布出 ...

ER-Studio的五种关系说明

1. identifying relationship: 1对多. 父实体的主键是子实体的外键(FK1),且FK1是主键. 2. no identifying, mandatory relations ...

Php使用sqlite

php sqlite文档:http://php.net/manual/en/book.sqlite.php sql:http://www.php100.com/html/webkaifa/PHP/PH ...

libcurl使用演示样例

简要说明:C++使用libcurl訪问"www.baidu.com".获取返回码和打印出http文件 /* * @ libcurl使用演示样例 * @ 2014.04.29 * @ ...

学习 node&period;js 搭建web服务器

开始 学习使用 node.js 首先完成搭建一个 web服务器.myweb.js var http = require('http'); var url = require('url'); var h ...

Qt之表格控件蚂蚁线

一.蚂蚁线 摘自互动百科:在图像影像软件中表示选区的动态虚线,因为虚线闪烁的样子像是一群蚂蚁在跑,所以俗称蚂蚁线.在Poshop,After Effect等软件中比较常见. 背景:用过excel的同学 ...

Siamese network 孪生神经网络

Siamese network 孪生神经网络 https://zhuanlan.zhihu.com/p/35040994 https://blog.csdn.net/shenziheng1/artic ...

C&plus;&plus; Windows API 读写INI文件

BOOL WritePrivateProfileString( LPCTSTR lpAppName, // INI文件中的一个字段名[节名]可以有很多个节名 LPCTSTR lpKeyName, // ...

linux学习笔记-目录相关知识

我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! linux的目录结构及作用是根据fhs标准定制的,以下列出一些常用的目录的作用,以及fhs官方网站的连接 FHS官方网站的连接: ...

jps报process information unavailable的解决办法

现象 启动Hadoop的时候使用jps检查进程 ,出现Process information unavailable的问题,如下 [root@vm8033 local]# jps -- process ...

linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...相关推荐

  1. 向linux内核增加新的系统调用,为linux内核添加新的系统调用

    为linux内核添加新的系统调用 作者:李志勇 更多精彩: 更多精彩: 开发平台:x86 ubuntu 目标平台:S3C6410 linux3.4.4 一.    打开内核源码目录下arch/arm/ ...

  2. 信号发送函数sigqueue和信号安装函数sigaction

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

  3. Linux信号编程实践(二) 信号发送函数和可重入函数

    在早期的UNIX中信号是不可靠的,不可靠在这里指的是:信号可能丢失,一个信号发生了,但进程却可能一直不知道这一点. 现在Linux 在SIGRTMIN实时信号之前的都叫不可靠信号,这里的不可靠主要是不 ...

  4. Linux系统的中断、系统调用和调度概述【转】

    转自:http://blog.csdn.net/yanlinwang/article/details/8169725 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近学习Linux操作系统, ...

  5. linux 时间系统 一 时间相关的系统调用

    linux 时间系统 一 时间相关的系统调用 时间相关的系统调用,这里主要说明的是用来记录时间(打时间戳)和delay时间的系统调用.它们是linux时间系统的一部分. 时间相关的操作在应用层和内核层 ...

  6. linux系统SIG_ERR函数的用法,信号(Signal)

    信号的基本概念 信号被认为是一种软件中断(区别于硬件中断),信号机制提供了一种在单进程/线程下处理异步事件的方法. 每个信号都有一个编号和一个宏定义名称 ,这些宏定义可以在 signal.h 中找到. ...

  7. linux wenj 立即生效_Linux系统调用(转载)

    目录: 1. Linux系统调用原理 2. 系统调用的实现 3. Linux系统调用分类及列表 4.系统调用.用户编程接口(API).系统命令和内核函数的关系 5. Linux系统调用实例 6. Li ...

  8. 2万字系统总结,带你实现 Linux 命令自由?

    前言 Linux 的学习对于一个程序员的重要性是不言而喻的.前端开发相比后端开发,接触 Linux 机会相对较少,因此往往容易忽视它.但是学好它却是程序员必备修养之一. 如果本文对你有所帮助,请点个 ...

  9. ​2万字系统总结,带你实现Linux命令自由

    来源:掘金- Lion https://juejin.cn/post/6938385978004340744 前言 Linux 的学习对于一个程序员的重要性是不言而喻的.前端开发相比后端开发,接触 L ...

最新文章

  1. 整理Silverlight资源列表(四)——Silverlight案例补充
  2. python创建脚本文件_python创建文件备份的脚本
  3. unity3d collider自动调整大小_Maya模型在Unity3d中的快速烘焙【2020】
  4. jquery miniui , 普加甘特图,流程管理
  5. java注解中可使用对象_Java注解(二):实战 - 直接使用对象列表生成报表...
  6. 对linux中多线程编程中pthread_join的理解
  7. Spring @Autowired 调用别的包下的Bean 解决方法
  8. mongodb中的3t客户端的时间延长做法
  9. pr用什么显卡比较好_用 PR 剪辑视频应该用什么 CPU 和显卡?
  10. 错误码errno和perror函数
  11. android app与gprs通信,gprs连接管理app
  12. 压缩包 zip RAR 7z 密码破解常用的几种方法
  13. 游戏中要遵守道德规范吗?谈《荒野大镖客2》道德体验设计的意义
  14. python提取excel前十行生成图_Python读取Excel数据生成图表 v2.0
  15. 外罚函数法(一):外罚函数的构造
  16. 数据库原理 ODBC概述
  17. SQL Server数据库中创建数据表及数据类型操作应用
  18. 【论文阅读 Journal of Financial Economics】Surprise election for Trump connections
  19. py229基于python的网上咖啡商城#毕业设计
  20. 数字货币搬砖之路(第一次踩坑)

热门文章

  1. bootstrap 新闻列表_kuapingUI 2.2 版本发布,跨屏 UI-bootstrap 大组件 UI 框架
  2. 给python点颜色青少年学编程_早晨送给自己的句子,句句经典励志!
  3. 多线程:pthread_cond_wait 实现原理
  4. 递归/分治:归并排序
  5. PHP-----PHP程序设计基础教程----第四章数组
  6. IIS7.5 HTTP 错误 500 调用loadlibraryex失败的解决方法
  7. win7,windowsXP安装mysql-5.1.49-win32,中文版、英文版,通吃
  8. SLAM之特征匹配(二)————RANSAC--------翻译以及经典RANSAC以及其相关的改进的算法小结
  9. “分布式哈希”和“一致性哈希”的概念与算法实现
  10. 设计模式C#描述——抽象工厂模式