信号集与屏蔽信号

news/2025/2/22 0:26:06/

1.信号集和信号集处理函数

信号集是一个位向量,其中每一位对应着linux系统的一个信号。可使用如下函数对信号集进行处理:

 

#include <signal.h>

int sigemptyset(sigset_t * set);

int sigfillset(sigset_t * set);

int sigaddset(sigset_t * set);

int sigdelset(sigset_t * set);

 

sigemptyset将一个信号集清空;sigfillset将信号集的所有位置位;sigaddset函数将参数signo指定的信号所对应的位设置为1;sigdelset将signo的对应位设置为0。

 

使用如下函数检测信号集的相应位是否被设置:

 

#include <signal.h>

int sigismember(sigset_t * set,int aigno);

 

返回值为1时,代表该位被设置,返回值为0时,代表该位未被设置,失败则返回-1。

 

//sigset.c 使用信号集处理函数测试并设置相应信号的位

#include <stdio.h>

#include <signal.h>

 

int main()

{

sigset_t sig_set;

sigemptyset(&sig_set);//清空信号集

sigaddset(&sig_set,SIGKILL-1);//设置SIGKILL的相应位

 

if(sigismember(&sig_set,SIGKILL))==1){

printf("SIGKILL has been set/n");

else

printf("can't set signal set/n");

 

return 0;

}

 

2.屏蔽信号

 

阻塞一些信号,使进程即使接收到信号,也不做处理。

 

使用如下函数:

 

#include <signal.h>

int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
函数说明 sigprocmask()可以用来改变目前的信号屏蔽,其操作依参数how来决定
SIG_BLOCK 新的信号屏蔽由目前的信号屏蔽和参数set 指定的信号屏蔽作联集
SIG_UNBLOCK 将目前的信号屏蔽删除掉参数set指定的信号屏蔽
SIG_SETMASK 将目前的信号屏蔽设成参数set指定的信号屏蔽。
如果参数oldset不是NULL指针,那么目前的信号屏蔽会由此指针返回。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EFAULT 参数set,oldset指针地址无法存取。
EINTR 此调用被中断

 

如果set的值为NULL,则无论how是何值都不会更改信号屏蔽字。这种方法用于得到当前进程的信号屏蔽字。

sigprocmask(0,NULL,&oset);

 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
 
void sigusr1_handler(int signo)
{
    printf("catch SIGUSR1/n");
}
 
int main(void)
{
    sigset_t set;
     
    if(signal(SIGUSR1, sigusr1_handler) == SIG_ERR){
        perror("can¡¯t set handler for SIGUSR1");
        exit(1);
    }
 
    sigemptyset(&set);//清空信号集
    sigaddset(&set, SIGUSR1 - 1);//设置SIGUSR1
 
    if(sigprocmask(SIG_BLOCK, &set, NULL) == -1){//屏蔽该信号
        perror("fail to set signal-mask");
        exit(1);
    }
     
    printf("SIGUSR1 is not available/n");
 
    sleep(10);//休眠,等待用户发送SIGUSR1信号
 
    if(sigprocmask(SIG_UNBLOCK, &set, NULL) == -1){ //恢复屏蔽的信号
        perror("fail to set signal-mask");
        exit(1);
    }
 
    printf("SIGUSR1 is available now/n");
 
    sleep(10);//休眠,等待用户发送SIGUSR1信号
 
    return 0;
}

 

 

3.处理未决信号

如果屏蔽了一个信号,但是进程还是从某处接收到了此信号,这种信号叫做未决的。这种信号是悬而未决的。

如果调用sigprocmask后有任何未决的但是已经不再阻塞的信号时,在该函数返回之前,至少会将这些解放了的未决信号中的一个发送给该进程。linux中使用sigpending函数检查未决信号,其函数的原型如下;

 

#include <signal.h>

int sigpending(sigset_t * set);

 

set表示当前进程中所有未决的信号。如果成功得到未决信号集,返回0,否则返回-1。

 

下例先阻塞SIGUSR1信号,之后向该进程发送SIGUSR1信号,此信号为未决的,使用sigpending函数测试是否有一个未决的SIGUSR1信号,最后取消对该信号的阻塞,处理这个信号。

 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
 
void sigusr1_handler(int signo)
{
    printf("catch SIGUSR1/n");
}
 
int main(void)
{
    sigset_t set;
    sigset_t sig_pend;
 
    sigemptyset(&set);
    sigemptyset(&sig_pend);
     
    if(signal(SIGUSR1, sigusr1_handler) == SIG_ERR){
        perror("can¡¯t set handler for SIGUSR1");
        exit(1);
    }
     
    sigaddset(&set, SIGUSR1 - 1); //添加SIGUSR1信号
     
    if(sigprocmask(SIG_BLOCK, &set, NULL) == -1){ //阻塞SIGUSR1
        perror("fail to set signal-mask");
        exit(1);
    }
     
    sleep(10); //休眠10,期间接收信号,注意进程休眠后不会被未决的信号唤醒
 
    if(sigpending(&sig_pend) == -1){  //得到所有的未决信号集
        perror("fail to get pending signal");
        exit(1);
    }
     
    if(sigismember(&sig_pend, SIGUSR1 - 1) == 1) //测试是否有SIGUSR1信号是未决的
        printf("there is a signal, SIGUSR1, is pending/n");
    else{
        perror("fail to test signal-set");
        exit(1);
    }
     
    if(sigprocmask(SIG_UNBLOCK, &set, NULL) == -1){ //取消对SIGUSR1的阻塞
        perror("fail to set signal-mask");
        exit(1);
    }
     
    printf("SIGUSR1 is available again/n");
 
    return 0;
}

 

 

4.高级信号处理函数

 

原型:

 

#include<signal.h>
定义函数 int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
函数说明 sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的所有信号。
如参数结构sigaction定义如下
struct sigaction
{
void (*sa_handler) (int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);
}
sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号搁置。
sa_restorer 此参数没有使用。
sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
OR 运算(|)组合A_NOCLDSTOP : 如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程SA_ONESHOT/SA_RESETHAND:当调用新的信号处理函数前,将此信号处理方式改为系统预设的方式。
SA_RESTART:被信号中断的系统调用会自行重启
SA_NOMASK/SA_NODEFER:在处理此信号未结束前不理会此信号的再次到来。如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction 返回。
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码 EINVAL 参数signum 不合法, 或是企图拦截SIGKILL/SIGSTOPSIGKILL信号
EFAULT 参数act,oldact指针地址无法存取。
EINTR 此调用被中断

 

 

5.SA_NOCLDWAIT选项

设置SA_NOCLDWAIT选项后,当信号为SIGCHILD时,则调用进程的子进程终止,立即释放系统资源。如果调用进程调用wait函数,则会导致该进程阻塞,知道其所有的子进程全部释放后wait函数返回-1,并将errno错误号设置为ECHILD,该选项可以用来避免僵尸进程的产生。

 

//nowait.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
 
int main(void)
{
    struct sigaction act;
    pid_t pid;
     
    act.sa_handler = SIG_DFL; 
    act.sa_flags = SA_NOCLDWAIT;
    act.sa_sigaction = NULL;
    sigemptyset(&act.sa_mask);
 
    if(sigaction(SIGCHLD, &act, NULL) == -1){
        perror("fail to set handler for SIGCHILD");
        exit(1);
    }
 
    pid = fork();
 
    if(pid < 0){
        perror("fail to fork");
        exit(1);
    }else if(pid == 0){
        printf("the 1st child/n");
        exit(0);//第一个进程立即退出
    }else{
        pid = fork();
 
        if(pid < 0){
            perror("fail to fork");
            exit(1);
        }else if(pid == 0){
            printf("the 2nd child/n");
            sleep(5);//休眠5秒退出
            exit(0);
        }else{
            if(wait(NULL) == -1)//调用wait函数,该函数必定出错返回
                if(errno == ECHILD)
                    printf("all child quit, no child is zome/n");
             
            printf("the parent/n");
        }
    }
     
    return 0;
}

 

执行:

 

 ./nowait
the 1st child
the 2nd child
all child quit, no child is zome
the parent

 

 

6.SA_NODEFER选项

如果设置SA_NODEFER选项,当捕捉到该信号时该信号正在执行处理函数时,不阻塞该信号,除非sa_mask中指定阻塞该信号。

 

//nodefer.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
 
void sigusr1_handler(int signo)
{
    printf("catch SIGUSR1/n");
 
    sleep(5);//等待下一个SIGUSR1信号
 
    printf("back to main/n");
}
 
int main(void)
{
    struct sigaction act;
         
    act.sa_handler = sigusr1_handler; 
    act.sa_flags = SA_NODEFER;
    act.sa_sigaction = NULL;
    sigemptyset(&act.sa_mask);
 
    if(sigaction(SIGUSR1,&act, NULL) == -1){
        perror("fail to set handler for SIGCHILD");
        exit(1);
    }
 
    printf("process begin/n");
 
    sleep(10);//等待SIGUSR1信号
 
    printf("done/n");
     
    return 0;
}

 

 

7.SA_RESETHAND选项

如果设置SA_RESETHAND选项,当信号处理返回后,该信号的处理函数乎恢复为默认的信号处理函数。

 

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
 
void sigusr1_handler(int signo)
{
    printf("catch SIGUSR1/n");
}
 
int main(void)
{
    struct sigaction act;
         
    act.sa_handler = sigusr1_handler; 
    act.sa_flags = SA_RESETHAND;
    act.sa_sigaction = NULL;
    sigemptyset(&act.sa_mask);
 
    if(sigaction(SIGUSR1, &act, NULL) == -1){
        perror("fail to set handler for SIGCHILD");
        exit(1);
    }
 
    printf("process begin/n");
 
    sleep(5);//等待第一个SIGUSR1
 
    sleep(5);//等待第二个SIGUSR1
 
    printf("done/n");
     
    return 0;
}


http://www.ppmy.cn/news/671544.html

相关文章

WiFi - 为啥WiFi信号的总是这么差?【附:解决方案】

一、为啥WiFi信号的总是这么差&#xff1f; 首先我们来看看WiFi信号在传播中遇到障碍物之后的反应&#xff1a; 折射&#xff1a;WiFi信号经过玻璃或水的时候&#xff0c;信号路径发生偏折&#xff0c;我们和路由器都在空气中&#xff0c;因此折射的影响可以忽略。反射&#x…

温馨提示: 高考信号屏蔽到底是个什么鬼?

如果这两天你手机信号不正常&#xff0c;恭喜你&#xff0c;您家是标准的学区房。祖国的花朵们即将走进高考考场&#xff0c;各地通信汪发来温馨提示&#xff1a; 所有手机用户&#xff0c;全国高考将于6月7日-8日进行&#xff0c;因考试期间各考点将开启大功率屏蔽仪&#xff…

全球WIFI功率(信号)最强的国家清单,无线WIFI调优

经常玩Merlin梅林或华硕路由器的朋友都知道&#xff0c;无线路由器有个国家地区选项&#xff0c;中文互联网中都在传说澳大利亚地区的无线信号最好&#xff0c;除了华硕这些全球品牌路由器厂商&#xff0c;还有网建Netgear、领势Linksys这些品牌也有调整路由器地区的功能&#…

解决WiFi信号弱小妙招

解决WiFi信号弱小妙招 在生活中我们会遇到这样的情况&#xff1a;自己的房间离路由器离卧室很远&#xff0c;当你到自己的房间里想打一句紧张刺激的王者荣耀或想刷个视频时你的WiFi信号已经所剩无几&#xff0c;今天就教大家一个解决此问题的办法&#xff01; 工具&#xff1a…

HDMI 接口干扰WiFi 信号

HDMI 使用74.2MHz 频率时&#xff0c;其33 倍频正好处于WiFi 的2.4G 频段内&#xff0c;会严重的干扰WiFi 信号。如果使用148.5MHz 频率&#xff0c;虽然其16 倍频没有处于WiFi 频段内&#xff0c;但是由于频率的隔离度也不好&#xff0c;也会在一定程度上干扰WiFi 的信号。 …

如何提高wifi模块的抗干扰能力

随着物联网的快速发展&#xff0c;我们的生活变得非常的智能、方便&#xff0c;可以说我们的生活现在已经离不开物联网了&#xff0c;那么无线模块和物联网有什么关系呢&#xff1f; 无线模块是物联网中一个重要的核心&#xff0c;它是链接物联网感知层和网络层的关键环节&…

无线信号穿墙能力

无线信号给房屋墙壁阻挡是有什么原因&#xff1f;无线信号穿墙能力是什么意思&#xff1f;对于无线网络的初涉者来说很可能会提出这样的问题。 无线信号穿墙能力 在无线局域网技术中之所以有“穿墙能力”和“墙壁阻挡”的概念是因为无线局域网技术所采用的无线频段决定的。 由…

如何检测家里的WIFI网络信号?

网络信号检测&#xff0c;一般信号强度在-30~-120之间&#xff0c;-35已经很强了&#xff0c;基本上没什么衰减&#xff0c;非常好的网络连接了。正常信号强度&#xff0c;-40 dbm ~ -85 dbm之间&#xff0c;小于 -90 dbm 就很差了&#xff0c;几乎没法连接。 有哪些软件可以免…