可靠信号的用法

signal() 函数只能提供简单的信号安装操作,使用该函数处理信号比较简单,只要把要处理的信号和处理函数列出即可。signal() 函数主要用于从 Unix 继承过来的不可靠、非实时信号的处理,并且不支持信号传递信息。Linux 提供了功能更强大的 sigaction() 函数,此函数可以用来检查和更改信号处理操作,可以支持可靠、实时信号的处理,并且支持信号传递信息。

先看 kill() 的升级版:

#include <signal.h>

/* 功能:给指定进程发送信号 */
int sigqueue(pid_t pid, int sig, const union sigval value);

/* 参数:
    pid: 进程号。
    sig: 信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令 kill -l ("l" 为字母)进行相应查看。
    value: 通过信号传递的参数。
*/

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

/* 返回值:
    0:成功
    -1:失败
*/

在看 signal() 的升级版:

#include <signal.h>

/* 功能:检查或修改指定信号的设置(或同时执行这两种操作)。*/
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

/* 参数:
    signum:要操作的信号。
    act:   要设置的对信号的新处理方式(设置)。
    oldact:原来对信号的处理方式(设置)。

    如果 act 指针非空,则要改变指定信号的处理方式(设置),如果 oldact 指针非空,则系统将此前指定信号的处理方式(设置)存入 oldact。
*/

/* 现在 struct sigaction 被定义得比较复杂,简化一下如下: */
struct sigaction  
{  
    /*旧的信号处理函数指针*/  
    void (*sa_handler)(int signum) ;  
    /*新的信号处理函数指针*/  
    void (*sa_sigaction)(int signum, siginfo_t *info, void *context);  
    /*信号阻塞集*/ 
    sigset_t sa_mask; 
    /*信号处理的方式*/  
    int sa_flags;
    /*这个暂时不用管*/
    void (*sa_restorer) (void);
}; 
/* 
sa_handler、sa_sigaction:信号处理函数指针,和 signal() 里的函数指针用法一样,应根据情况给 sa_sigaction、sa_handler 两者之一赋值,其取值如下:
    SIG_IGN:忽略该信号
    SIG_DFL:执行系统默认动作
    处理函数名:自定义信号处理函数
信号处理函数定义为如下形式:
void (*sa_sigaction)( int signum, siginfo_t *info, void *context );
    signum:信号的编号。
    info:记录信号发送进程信息的结构体。
    context:可以赋给指向 ucontext_t 类型的一个对象的指针,以引用在传递信号时被中断的接收进程或线程的上下文。

sa_mask:信号阻塞集 

sa_flags:用于指定信号处理的行为,它可以是一下值的“按位或”组合:
    SA_RESTART:使被信号打断的系统调用自动重新发起(已经废弃)
    SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
    SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
    SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
    SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
    SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。
*/

/* 返回值:
    成功:0
    失败:-1
*/

代码

/* study.cpp 发送程序 */
#include <stdio.h>  
#include <stdlib.h>
#include <signal.h>  
#include <sys/types.h>  
#include <unistd.h>  

int main(int argc, char *argv[])  
{  
    if(argc >= 2)  
    {  
        pid_t pid,pid_self;  
        union sigval tmp;  
  
        /* 将命令参数转化为进程号 */
        pid = atoi(argv[1]);
        /* 用命令参数作为传递值 */
        tmp.sival_int = atoi(argv[2]);
          
        /* 给进程 pid,发送 SIGINT 信号,并把 tmp 传递过去 */  
        sigqueue(pid, SIGINT, tmp);  
          
        pid_self = getpid();  
        printf("pid = %d, pid_self = %d\n", pid, pid_self);  
    }  
      
    return 0;  
}
/* main.c 接收程序 */
#include <signal.h>  
#include <unistd.h>
#include <stdio.h>  
  
/* 信号处理回调函数 */   
void signal_handler(int signum, siginfo_t *info, void *ptr)  
{  
    printf("signum = %d\n", signum);
    /* 发送信号的进程的进程号 */
    printf("info->si_pid = %d\n", info->si_pid);
    /* 对方传递过来的信息  */
    printf("info->si_sigval = %d\n", info->si_value.sival_int);  
}  
  
int main(int argc, char *argv[])  
{  
    struct sigaction act, oact;  
    /* 指定信号处理回调函数 */ 
    act.sa_sigaction = signal_handler;  
    /* 设置阻塞集为空 */
    sigemptyset(&act.sa_mask); 
    /* 使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。 */
    act.sa_flags = SA_SIGINFO;   
      
    /* 注册信号 SIGINT   */
    sigaction(SIGINT, &act, &oact);  
      
    while(1)  
    {  
        printf("pid is %d\n", getpid()); 
	/* 捕获信号,此函数会阻塞  */
        pause(); 
    }  
    return 0;  
}  

先执行:

[lingyun@manjaro study]$ gcc main.c -o main
[lingyun@manjaro study]$ gcc study.cpp -o study
[lingyun@manjaro study]$ ./main
pid is 13758

再在另一个命令窗口执行:

[lingyun@manjaro study]$ ./study 13758 777
pid = 13758, pid_self = 13761
[lingyun@manjaro study]$ ./study 13758 7775
pid = 13758, pid_self = 13762

第一个命令窗口会得到一些信息,可见接受进程接收到了发送进程发送的信号以及一些信息,如 info->si_sigval. 另外,siginfo_t *info 这个结构体里面还有很多其他信息,可以看看。

[lingyun@manjaro study]$ gcc main.c -o main
[lingyun@manjaro study]$ gcc study.cpp -o study
[lingyun@manjaro study]$ ./main
pid is 13758
signum = 2
info->si_pid = 13761
info->si_sigval = 777
pid is 13758
signum = 2
info->si_pid = 13762
info->si_sigval = 7775

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值