_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); |
- 您如何"捕获SIGINT信号"?
-
@KerrekSB,我已经更新了问题
-
如果您使用sigaction(将sa_flags归零)而不是signal,那么一切正常吗?
-
@MarkPlotnick,是的,这有帮助!你能解释一下区别吗?
-
我会写一个答案。简短版本:_GNU_SOURCE为您提供许多功能的BSD版本,如果使用signal,则包括BSD "安全信号"。 sigaction(OTOH)使您可以用标志指定是否重新启动系统调用。
-
在多线程程序中调用signal是UB。
-
@KerrekSB,sigaction的UB是否相同?
-
@Leonidas:不,sigaction很好。
在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具有未指定的行为。