现在的位置: 首页 > 综合 > 正文

关于c/c++中信号传送数据函数sigqueue的认识

2016年12月10日 ⁄ 综合 ⁄ 共 2999字 ⁄ 字号 评论关闭

最近学习unix系统信号时候遇到了函数sigqueue函数,网上看了看一切前辈写的感觉思路挺清晰的,但是自我感觉理解不是很清楚,我就在这唠叨两句,留着以后复习用。(用的是ubuntu14.04系统测试)

    首先呢,看下它的原型吧:

       #include <signal.h>
       int sigqueue(pid_t pid, int sig, const union sigval value);

     第一个参数:指定要发送给进程的 id号(注:pid_t就是)

     第二个参数:发送的信号值,也就是你要发送的信号类型

    第三个参数:是一个联合类型的值,          

  定义如下:

  union sigval {
               int   sival_int;                
               void *sival_ptr;                        

           };

所以可以用下边的方式发送信号:比如我要给 进程100 发送 信号2(SIGINT),传送的数值为 50

sigqueue(100,SIGINT,50);

这样进程100 就能接受信号了

但是接收端,要接收带数据的信号必须用sigaction()这个函数。

它的定义如下(注:unix环境高级变成上函数定义在*前有个restrict关键字,就是一 类型限定符)

 #include <signal.h>

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

第一个参数:就是要接收的信号

第二个参数:是一个sigaction的结构体定义如下

struct sigaction {
               void     (*sa_handler)(int);//对信号采用什么处理方式
               void     (*sa_sigaction)(int, siginfo_t *, void *);//同上,下边会详细说明
               sigset_t   sa_mask;//设置要屏蔽的信号
               int        sa_flags;//设置其他标志
               void     (*sa_restorer)(void);//好像是保留的,
           };

东西太多了,只说说这次用到的一些东西,要想让函数使用第二个函数指针,就需要设置sa_flags为SA_SIGINFO
第三个参数:跟第二个参数一样都是结构体指针,但是第二个是带入数据,后一个传出数据的。

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

这个函数指针就是用来通过信号接受数据,当信号传送过来时候,进程内部会把通过传送端传送的value值放到结构体siginfo中

然后把传送端的相关信息也记录到siginfo这个结构体中,然后把这个siginfo结构体的地址当做参数给函数(*sa_sigaction)();

(注:向int (*p)(int a)这个函数指针要调用函数的话,原型应该就是 (*p)(10)这样调用,一般都省略了外边的*,所以一般都是p(10)调用一个函数)

在手册中siginfo_t结构体是这样定义的:

//在不同环境中,这个结构体可能会有所不同
siginfo_t {
               int      si_signo;    /* Signal number */
               int      si_errno;    /* An errno value */
               int      si_code;     /* Signal code */
               int      si_trapno;   /* Trap number that caused
                                        hardware-generated signal
                                        (unused on most architectures) */
               pid_t    si_pid;      /* Sending process ID *///发送端进程id这个我能看懂
               uid_t    si_uid;      /* Real user ID of sending process */
               int      si_status;   /* Exit value or signal */
               clock_t  si_utime;    /* User time consumed */
               clock_t  si_stime;    /* System time consumed */
               sigval_t si_value;    /* Signal value */发送端发送的数值
               int      si_int;      /* POSIX.1b signal */
               void    *si_ptr;      /* POSIX.1b signal */
               int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
               int      si_timerid;  /* Timer ID; POSIX.1b timers */
               void    *si_addr;     /* Memory location which caused fault */
               long     si_band;     /* Band event (was int in
                                        glibc 2.3.2 and earlier) */
               int      si_fd;       /* File descriptor */
               short    si_addr_lsb; /* Least significant bit of address
                                        (since Linux 2.6.32) */
           }

我只把用得着的翻译了一下(英语才4级,太菜了)

sigval_t    value中sigval是一个联合union sigval {
               int   sival_int;
               void *sival_ptr;
           };

还是举个例子吧,当时看得时候也费劲了好久,

发送端:通过信号2,向进程传送一个数100

  1 #include<stdio.h>
  2 #include<signal.h>
  3 int main(int argc,char *argv[])
  4 {
  5         printf("我是进程%d发送端>>\n",getpid());
  6         union sigval value;
  7         value.sival_int = 100;
  8         sigqueue(atoi(argv[1]),2,value);
  9                 //向进程发送信号2数值为100,其中进程由用户输入
 10         return 0;
 11 }
~     

接受端:通过信号2,接收来自其他进程的数据

  1 #include<stdio.h>
  2 #include<signal.h>
  3 #include<unistd.h>
  4 void fa(int signo,siginfo_t *info,void *p )
  5 {
  6         printf("通过信号%d,收到来自%d进程的数%d\n",signo,info->si_pid,info-    >si_value.sival_int);
  7 }
  8 int main()
  9 {
 10         printf("我是进程%d接收端>>>\n",getpid());
 11         struct sigaction act;
 12         sigemptyset(&act.sa_mask);//设置不屏蔽信号
 13         act.sa_sigaction = fa;//把处理函数的地址给函数指针
 14         act.sa_flags = SA_SIGINFO;//设置用第二个处理函数
 15         sigaction(2,&act,NULL);
 16         while(1);
 17 }
运行结果如下: 

在发送过程中,发送端的信息比如,进程号,数值,信号值都被存到结构体sigaction中,然后被作为参数传送给了函数指针,

函数就能直接打印出来了,当然要对数值进行何种操作就是程序员自己的事了。

有不足之处大家多多指点,本人刚接触unix环境编程。


抱歉!评论已关闭.