首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Signals - c99与gnu99

Signals - c99与gnu99
EN

Stack Overflow用户
提问于 2011-11-28 03:00:14
回答 3查看 1.6K关注 0票数 3

我有以下代码。当我使用gnu扩展(-std=gnu99)编译它时,程序将在结束之前捕获5SIGINT(我希望如此)。在没有它的情况下编译时(-std=c99)在第二行之后结束(并且只输出一行)。

我遗漏了什么?

代码语言:javascript
复制
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

int int_stage = 0;
int got_signal = 0;

void sigint(int parameter)
{
  (void)parameter;
  got_signal = 1;
  int_stage++;
}

int main()
{
  signal(SIGINT,sigint);

  while(1)
  {
    if (got_signal)
    {
      got_signal = 0;
      puts("still alive");
      if (int_stage >= 5) exit(1);
    }
  }
  return 0;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-11-28 03:11:59

使用sigaction(2)而不是signal(2)

Linux手册页的可移植性部分特别包含以下内容:

在最初的UNIX系统中,当通过传递信号来调用使用signal()建立的处理程序时,该信号的处理将被重置为SIG_DFL,并且系统不会阻止该信号的进一步实例的传递。System V也为signal()提供了这些语义。这很糟糕,因为在处理程序有机会重新建立自己之前,信号可能会再次传递。此外,相同信号的快速传递可能导致处理程序的递归调用。

BSD通过更改信号处理的语义改进了这种情况(但不幸的是,在使用signal ()建立处理程序时,它默默地更改了语义)。在BSD上,当调用信号处理程序时,不会重置信号处理,并且在处理程序执行时阻止传递信号的更多实例。

Linux上的情况如下:

  • 内核的signal()系统调用提供了system V语义。
  • 默认情况下,在glibc 2和更高版本中,signal()包装函数不会调用内核系统调用。相反,它使用提供BSD语义的标志调用sigaction(2)。只要定义了_BSD_SOURCE功能测试宏,就会提供此默认行为。默认情况下,_BSD_SOURCE是定义的;如果定义了_GNU_SOURCE,它也是隐式定义的,当然也可以显式定义。

在glibc 2和更高版本上,如果未定义信号特性测试宏,则_BSD_SOURCE ()提供System V语义。(请参见feature_test_macros(7).),如果在_BSD_SOURCE的标准模式之一(-std=xxx或-ansi)中调用gcc(1)或定义各种其他功能测试宏(如_POSIX_SOURCE、_XOPEN_SOURCE或_SVID_SOURCE),则不会提供默认的隐式定义_XOPEN_SOURCE

使用std=gnu99,您将获得BSD语义。使用-std=c99,您将获得System V语义。因此,在一种情况下(BSD)“重新安装”信号处理程序,而在另一种情况下(System V)将信号处理程序重置回SIG_DFL。

票数 6
EN

Stack Overflow用户

发布于 2011-11-28 03:17:45

问题是signal还会重置信号处理机制,您必须将sigint重置为信号处理程序。从手册中

在最初的UNIX系统中,当通过传递信号来调用使用signal()建立的处理程序时,该信号的处理将被重置为SIG_DFL,并且系统不会阻止该信号的进一步实例的传递。System V也为signal()提供了这些语义。这很糟糕,因为在处理程序有机会重新建立自己之前,信号可能会再次传递。此外,相同信号的快速传递可能导致处理程序的递归调用。

这就是如何使用旧的过时的signal()调用来实现它。注意int_stage和got_signal必须是sig_atomic_t的,你也可以只调用异步安全函数,查看here的列表。

代码语言:javascript
复制
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

sig_atomic_t int_stage = 0;  
sig_atomic_t got_signal = 0;

void sigint(int parameter)
{
  (void)parameter;
  got_signal = 1;
  int_stage++;
}

int main()
{
   signal(SIGINT,sigint);

   while(1)
   {
      if (got_signal)
      {
       signal(SIGINT,sigint);
       got_signal = 0;
       puts("still alive");
       if (int_stage >= 5) exit(1);
    }
 }
 return 0;
}

请考虑使用sigaction或sigwait。

Sigaction实际上也有同样的想法,但重新初始化信号处理程序并不是胡说八道。Sigwait会停止你的线程,直到收到一个信号。因此,对于sigwait,您可以调用任何函数或处理任何数据。如果您愿意,我可以向您展示示例代码。

票数 2
EN

Stack Overflow用户

发布于 2011-11-28 03:12:20

我同意Ethan Steinberg的观点--“忙碌的等待”是非常错误的。

但问题是您无法重置信号处理程序。AFAIK,您必须使用任何版本的C执行此操作(再次调用"signal(SIGINT,sigint)“)。

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

https://stackoverflow.com/questions/8288164

复制
相关文章

相似问题

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