信号的屏蔽,信号集

Posted 邶风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了信号的屏蔽,信号集相关的知识,希望对你有一定的参考价值。

1、信号集

POSIX标准定义了数据类型sigset_t 

#include <signal.h>

int sigemptyset(sigset_t *set);

初始化一个信号集,使其不包括任何信号

int sigfillset(sigset_t *set);

用来初始化一个信号集,使其包括所有信号

int sigaddset(sigset_t *set, int signum);

用来向set指定的信号集中添加由signum指定的信号

int sigdelset(sigset_t *set, int signum);

用来从set指定的信号集中删除由signum指定的信号

int sigismember(const sigset_t *set, int signum);

用来测试信号signum是否包括在set指定的信号集中

2、信号屏蔽
int sigpending(sigset_t *set);

int sigsuspend(const sigset_t *mask);

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

(1)sigprocmask函数int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

每个进程都有一个信号屏蔽码,它规定了当前阻塞而不能传递给该进程的信号集,调用函数sigprocmask可以检测或更改进程的信号屏蔽码。

如果oldset是非空的,则该进程之前的信号屏蔽码通过oldset返回;如果参数set是非空指针,则该函数将根据参数how来修改当前屏蔽码,how

的取值如下:

The behavior of the call is dependent on the value of how, as follows.

SIG_BLOCK
The set of blocked signals is the union of the current set and the set argument.

将进程新的信号屏蔽码设置为当前信号屏蔽码和set指向信号集的并集

SIG_UNBLOCK
The signals in set are removed from the current set of blocked signals. It is permissible to attempt to unblock a signal which is not blocked.

将进程新的信号屏蔽码设置为当前信号屏蔽码中,删除set所指向信号集,即set包含了我们希望解除阻塞的信号。即使

对当前信号屏蔽码中不存在的信号使用SIG_UNBLOCK也是合法操作。

SIG_SETMASK
The set of blocked signals is set to the argument set.

将进程新的信号屏蔽码设置为set指向的值

(2)sigpending函数int sigpending(sigset_t *set);

函数sigpending用来获取调用进程因被阻塞而不能传递和当前未决的信号集。该信号集通过参数set返回

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

void hand_signal(int signo)
{
    printf("rece SIGINT\n");
}


int main()
{
    sigset_t newmask, oldmask, pendmask;

    signal(SIGINT, hand_signal);

    //收到信号之后会被唤醒
    sleep(30);

    sigemptyset(&newmask);
    sigaddset(&newmask, SIGINT);

    //屏蔽信号SIGINT
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);

    //不会被SIGINT信号唤醒
    sleep(10);

    //获取未决信号队列
    sigpending(&pendmask);
    //检查未决信号队列中是否有SIGINT
    switch(sigismember(&pendmask, SIGINT))
    {
        case 0:
        {
            printf("the SIGINT is not in pending queue\n");
            break;
        }
        case 1:
        {
            printf("the SIGINT is in pending queue\n");
            break;
        }
        default:
            break;
    }

    //恢复屏蔽码
    sigprocmask(SIG_SETMASK, &oldmask, NULL);


    while(1);

    return 0;
}

 

 

(3)sigsuspend函数int sigsuspend(const sigset_t *mask);

将进程的信号屏蔽码设置为mask,然后与pause函数一样等待信号的发生并执行完信号处理函数。

信号处理函数执行完后再把进程的信号屏蔽码设置为原来的屏蔽字,然后sigpending函数才返回。

sigpending函数保证改变进程的屏蔽码和将进程挂起等待信号是原子操作。

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

void hand_signal(int signo)
{
    printf("rece SIGINT\n");
}


int main()
{
    sigset_t newmask, oldmask, zeromask;

    signal(SIGINT, hand_signal);

    sigemptyset(&newmask);
    sigemptyset(&zeromask);
    sigaddset(&newmask, SIGINT);

    //屏蔽信号SIGINT
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);

    //临界区
    //使用sigsuspend取消所有信号的屏蔽并等待信号的触发
    sigsuspend(&zeromask);

    /*
    sigprocmask(SIG_SETMASK, &oldmask, NULL);
    pause();
    */

    sigprocmask(SIG_SETMASK, &oldmask, NULL);


    while(1);

    return 0;
}

 

如果使用

    sigprocmask(SIG_SETMASK, &oldmask, NULL);
    pause();
会存在潜在debug,如果信号发生在sigprocmask之后,pause之前,则这个信号就会丢失掉了,且如果信号只发生一次,程序将永远挂起在pause上。
 

以上是关于信号的屏蔽,信号集的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp Linux的信号集操作,操作信号屏蔽字(阻塞信号集),读取未决信号集

SylixOS的信号屏蔽浅析

IPC方法-信号

如何让MAC屏蔽SIGPIPE信号?

Linux进程间通信 -- 信号集函数 sigemptyset()sigprocmask()sigpending()sigsuspend()

Linux--信号阻塞与屏蔽