关于C#:_GNU_SOURCE宏和epoll_wait行为

_GNU_SOURCE macro and epoll_wait behaviour

我在一个有多个线程的应用程序上工作。其中之一用于epoll。此应用程序还捕获SIGINT信号并执行一些终结操作。一切正常,直到我设置了_GNU_SOURCE宏。这会使程序卡在以下行:

1
int n = epoll_wait(epfd, events, N, -1);

因此,设置_GNU_SOURCE可以防止所有(recv也是)等待的呼叫在SIGINT上中断。为什么会这样呢?解决方法是什么?

尤其是我想使用sched_setaffinity。这需要CPU_SET,这仅在_GNU_SOURCE中可用。

更新

我如何捕捉SIGINT

1
2
3
4
static volatile int running = 1;
static void int_handler(int i) {
      running = 0;
}

然后在main

1
signal(SIGINT, int_handler);


在GNU / Linux上,/usr/include中的大多数非内核头文件都由提供glibc的相同软件包提供。当glibc提供函数的几种实现时,您可以使用诸如_GNU_SOURCE之类的feature_test_macros在各种实现中进行选择。

定义_GNU_SOURCE时,它还会定义_BSD_SOURCE,在较新版本的glibc中,它也定义_DEFAULT_SOURCE。定义这些宏后,头文件将为您提供某些功能的BSD版本。信号就是这些功能之一。

在UNIX的各种风格下,signal所做的事情略有不同。您遇到的区别是:某些"慢速"系统调用在发送信号时被中断时会发生什么。在V7和System III(和System V)上,处理程序返回后,系统调用将返回EINTR错误。在4.2BSD上,系统调用将重新启动。

如果使用POSIX标准签名而不是signal,则可以通过设置或清除struct sigaction \\的sa_flags中的SA_RESTART标志来选择系统调用是否可重新启动。

在glibc 2.19中,signal的System V版本最终以标志SA_RESTORER|SA_INTERRUPT|SA_NODEFER|SA_RESETHAND调用sigaction,而BSD版本以标志SA_RESTORER|SA_RESTART调用sigaction

使用sigaction的另一个原因:正如@KerrekSB所指出的,在多线程应用程序中使用signal具有未指定的行为。