linux信号编程实践

来源:互联网 发布:软件测试风险管理 编辑:程序博客网 时间:2024/04/19 11:51

简单的说,信号就是在软件层次上对中断机制的一种模拟,是一种异步通信方式。它可以实现内核进程和用户进程之间的交互。实现方式是,在任何时候发给某一进程,如果该进程没有处于执行态,则该信号由内核保存,直到该进程恢复执行再传递给它为止。如果一个信号进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

  使用kill -l选项列出系统所支持的所有信号列表。我的Redhat 9.0上如下:
  
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR 31) SIGSYS 33) SIGRTMIN 34) SIGRTMIN+1
35) SIGRTMIN+2 36) SIGRTMIN+3 37) SIGRTMIN+4 38) SIGRTMIN+5
39) SIGRTMIN+6 40) SIGRTMIN+7 41) SIGRTMIN+8 42) SIGRTMIN+9
43) SIGRTMIN+10 44) SIGRTMIN+11 45) SIGRTMIN+12 46) SIGRTMIN+13
47) SIGRTMIN+14 48) SIGRTMIN+15 49) SIGRTMAX-14 50) SIGRTMAX-13
51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9
55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5
59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1
63) SIGRTMAX

  可见信号值在31号前的有不同的名称,这些是不可靠信号(非实时信号);后面的都是以SIGRTMIN或者SIGRTMAX开头的信号,这些是为了解决前面“不可靠信号”的问题而进行了更改和扩充的信号,也称为实时信号。其中RT就是Real Time的简写形式。

1、信号的生命周期
 
一个完整的信号生命周期可以分为3个重要阶段,这三个重要阶段由4个重要事件来刻画:信号产生、信号在进程中注册、信号在进程中注销、执行信号处理函数。相邻两个事件的时间间隔构成信号生命周期的一个阶段。
 
2、信号处理过程
 
一个不可靠信号的处理过程如下:若发现该信号已经在进程中注册,就忽略该信号,所以,若前一个信号还未注销又产生了相同的信号就会造成信号丢失。
 
一个可靠信号的处理过程如下:可靠信号发送给进程,不管该信号是否已经在进程中注册,都会被再注册一次,因此信号不会丢失。
 
所有可靠信号都支持排队,而不可靠信号不支持排队。
 
3、用户进程对信号的响应形式
 
(1)忽略信号,除SIGKILL、SIGSTOP。
(2)捕捉信号,定义信号处理函数,当信号发生则执行相应的处理函数。
(3)缺省操作。
 
4、信号发送函数
 
kill() raise() alarm() pause()
 
实例一:保证子进程不在父进程调用kill之前退出
 
 
/*
 * kill.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

int main()
{
    pid_t pid;

    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }
    /*child*/
    else if (pid == 0) {
        raise(SIGSTOP);
        exit(0);
    }
    /*father*/
    else {
        printf("pid = %d/n", pid);
        if (waitpid(pid, NULL, WNOHANG) == 0) {
            if (kill(pid, SIGKILL) == 0) {
                printf("kill %d/n", pid);
            }
            else {
                perror("kill");
                exit(1);
            }
        }/*if*/
    }/*else*/

    return 0;
}

执行结果:

[armlinux@lqm kill]$ ./mykill
pid = 2032
kill 2032

实例二:利用alarm完成sleep功能

/*
 * alarm.c
 */

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

void my_alarm_handle(int sign_no)
{
    if (sign_no == SIGALRM) {
        printf("I have been waken up./n");
    }
}

int main()
{
    printf("sleep for 5s ... .../n");
    signal(SIGALRM, my_alarm_handle);

    alarm(5);
    pause();

    return 0;
}

执行结果:

[armlinux@lqm alarm]$ ./myalarm
sleep for 5s ... ...

等待5秒钟后执行处理函数,打印输出下面内容:
I have been waken up.

5、信号处理集函数组

sigemptyset:初始化信号集合为空

sigfillset:初始化信号集合为所有信号的集合

sigaddset:将指定信号加入到信号集合中去

sigdelset:将指定信号从信号集中删去

sigismember:查询指定信号是否在信号集合之中

sigprocmask:判断检测或更改信号屏蔽字

sigaction:用于改变进程接收到特定信号之后的行为

实践三:练习信号处理集函数

/*
 * 信号集函数组练习
 * 数据结构sigaction
 * struct sigaction {
 * void (*sa_handler)(int signo);
 * sigset_t sa_mask;
 * int sa_flags;
 * void (*sa_restore)(void);
 * }
 */

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

/*自定义SIGINT的处理函数,如果你按ctrl+c,则会打印提示,而不是默认的退出*/
void my_func(int sigo_num)
{
    printf("If you want to quit, please try 'ctrl+//' ./n");
}

int main()
{
    sigset_t set;
    struct sigaction action1, action2;

    /*初始化信号集为空*/
    if (sigemptyset(&set) < 0) {
        perror("sigemptyset");
        exit(1);
    }

    /*将相应的信号加入信号集*/
    if (sigaddset(&set, SIGQUIT) < 0) {
        perror("sigaddset SIGQUIT");
        exit(1);
    }
    if (sigaddset(&set, SIGINT) < 0) {
        perror("sigaddset SIGINT");
        exit(1);
    }

    /*设置信号屏蔽字*/
    if (sigprocmask(SIG_BLOCK, &set, NULL) < 0) {
        perror("sigprocmask SIG_BLOCK");
        exit(1);
    }
    else {
        printf("blocked,and sleep for 5s .../n");
        sleep(5);
    }
    if (sigprocmask(SIG_UNBLOCK, &set, NULL) < 0) {
        perror("sigprocmask SIG_UNBLOCK");
        exit(1);
    }
    else {
        printf("unblock/n");
        /*此处可以添加函数功能模块process()*/
        sleep(2);
        printf("If you want to quit this program, please try .../n");
    }

    /*对相应的信号进行循环处理*/
    while (1) {
        if (sigismember(&set, SIGINT)) {
            sigemptyset(&action1.sa_mask);
            action1.sa_handler = my_func;
            sigaction(SIGINT, &action1, NULL);
        }
        else if (sigismember(&set, SIGQUIT)) {
            sigemptyset(&action2.sa_mask);
            /*SIG_DFL采用缺省的方式处理*/
            action2.sa_handler = SIG_DFL;
            sigaction(SIGTERM, &action2, NULL);
        }
    }

    return 0;
}

执行处理:

[armlinux@lqm sigaction]$ ./sigaction
blocked,and sleep for 5s ...
unblock
If you want to quit this program, please try ...
If you want to quit, please try 'ctrl+/' .
退出

原创粉丝点击