首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >中断中C-中断中的信号处理

中断中C-中断中的信号处理
EN

Stack Overflow用户
提问于 2012-04-11 01:56:22
回答 2查看 7K关注 0票数 5

我在想,当我的程序同时处理其他信号时,是否有可能被一个信号中断,我尝试用以下方式模拟:

代码语言:javascript
运行
复制
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>

void sig_output()
{
    sigset_t set;
    sigprocmask(0,NULL,&set);
    printf("currently blocking:");
    if (sigismember(&set,SIGUSR1))
        printf("\nSIGUSR1");
    if(sigismember(&set,SIGUSR2))
        printf("\nSIGUSR2");
    printf("\n");
    return ;
}

void sig_handler(int sig)
{
    raise(SIGUSR1);    
    printf("start\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end\n");
    return ;
}

void other_sig_handler(int sig)
{  
    printf("start - other\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end - other\n");
    return ;
}

int main()
{
    sig_output();
    struct sigaction a;
    a.sa_handler=sig_handler;
    a.sa_flags=0;
    sigset_t set,old;
    //blocking SIGUSR1,SIGUSR2
    sigemptyset(&set);
    sigaddset(&set,SIGUSR1);
    sigaddset(&set,SIGUSR2);
    printf("blocking SIGUSR1, SIGUSR2\n");
    sigprocmask(SIG_SETMASK,&set,&old);
    sig_output();
    //adding handles for SIGUSR1,SIGUSR2
    sigemptyset(&(a.sa_mask));
    sigaction(SIGUSR1,&a,NULL);
    a.sa_handler=other_sig_handler;
    sigaction(SIGUSR2,&a,NULL);
    printf("poczatek wysylania \n");
    raise(SIGUSR1);
    raise(SIGUSR2);
    raise(SIGUSR1);
    printf("using sigsuspend\n");
    sigsuspend(&old);
    printf("end of program\n");
    return 0;
}

每次我运行这个程序,我就会得到

代码语言:javascript
运行
复制
currently blocking:
blocking SIGUSR1, SIGUSR2
currently blocking:
SIGUSR1
SIGUSR2
raising
using sigsuspend
start - other
SIGUSR2
end - other
start
SIGUSR1
end
end of program

总是这样吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-04-11 02:07:52

引用sigaction(2)手册页:

信号例程通常使用导致其调用被阻塞的信号执行,但仍可能出现其他信号。全局信号掩码定义了当前阻止传递到进程的一组信号。进程的信号掩码由其父进程的信号掩码初始化(通常为空)。它可以通过sigprocmask(2)调用进行更改,也可以在向进程传递信号时更改。

您可以使用SA_NODEFER标志控制是否在信号处理程序中自动阻止信号。

票数 6
EN

Stack Overflow用户

发布于 2012-04-11 02:18:45

据我所知,这些特定的待决信号的传递顺序并没有定义。然而,除了实时信号之外,信号是“非排队”的(大多数情况下;SIGCLD例外,传统上是通过“作弊”来完成的)。非排队方面意味着,如果你阻塞了信号X,然后raise它两次(就像上面对SIGUSR1所做的那样),你只会得到一次发送。

至少在一个系统(MacOS)上记录的唯一订购是:

代码语言:javascript
运行
复制
If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.

(就像SIGSEGVSIGBUS一样。)通常,您可以通过使用信号阻塞掩码来控制传送顺序:在某个点上解除对任何特定信号的阻塞,这些信号就是在该点上可以传送的信号。

如果不设置SA_NODEFER,处理程序入口处的阻塞掩码将始终阻塞处理程序正在处理的任何信号,因此您不必担心递归问题。

SIGCLD的特殊情况来自System V,它最初是通过在每次SIGCLD交付时将处理程序重置为SIG_DFL来实现这一点的。(实际上,无论您是否愿意,SysV对所有信号都做到了这一点,有效地实现了SA_RESETHAND。)默认操作是丢弃信号,就好像处理程序是SIG_IGN一样。当然,当多个子进程在处理程序可以完成它的事情之前完成时,这就产生了竞争条件。不过,SysV人员并没有使用阻塞/解锁模型,而是加入了一个技巧:在SIGCLD处理程序的末尾,您可以调用signal(SIGCLD, handler);来修复该处理程序。此时,如果有任何退出的子级尚未执行wait-ed,SysV将立即生成一个新的SIGCLD,并以递归方式进入您的处理程序。这使得信号看起来像是在排队,而实际上并没有排队。

有关Linux信号的更多信息,请参阅(例如) http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10093907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档