在Linux手册中,signal(7)手册页的“描述”的最后一部分,(https://man7.org/linux/man-pages/man7/signal.7.html)它说被信号中断的对 pthread_cond_wait 的调用将失败并返回 EINTR(除非在处理程序中设置了 sa_restart)
再次在Linux手册中,在pthread_cond_wait(3) (https://man7.org/linux/man-pages/man3/pthread_cond_wait.3p.html)页面中它说:
这些函数不应返回错误代码 [EINTR]。
这两页不是矛盾吗?
在我的 Mac 上,使用命令行手册我什至找不到页面 signal(7),并且 pthread_cond_wait(2) 页面没有有关 EINTR 失败的信息。
我在MacOS上用以下代码做了测试:
int main(){
struct sigaction siga;
memset(&siga, 0, sizeof(siga));
siga.sa_handler = handle;
sigaction(SIGINT, &siga, NULL);
pthread_t thread;
pthread_create(&thread, 0, task, NULL);
sleep(2);
pthread_kill(thread, SIGINT);
pthread_join(thread, NULL);
printf("Ended\n");
return 0;
}
void *task(void * arg){
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_mutex_lock(&mutex);
errno = 0;
int res = pthread_cond_wait(&cond, &mutex);
printf("res = %d\n", res);
printf("errno = %d\n", errno);
return 0;
}
void handle(int arg){
}
输出为:
res = 0
errno = 260
Ended
我不知道这个输出意味着什么。 我认为260甚至超出了系统错误的范围。
那么这在 Linux 和 MacOS 中实际上是如何工作的呢?
这两页不是矛盾吗?
差不多,但请参阅下文。
根据经验,您应该选择更具体的来源而不是更笼统的来源。在这种情况下,这意味着依赖
pthread_cond_wait()
的手册页来获取有关该函数行为的信息。此外,我注意到您链接的 pthread_cond_wait
手册页回响了 该函数的 POSIX 规范,并且这两个来源也说:
如果将信号传递到等待条件变量的线程,则从信号处理程序返回后,线程将恢复等待条件变量,就好像它没有被中断一样,否则它将由于虚假唤醒而返回零。
您报告:
我在 MacOS 上使用以下代码进行了测试 [...]
输出为:
res = 0 errno = 260 Ended
我不知道这个输出意味着什么。
这意味着当被信号中断时,您的
pthread_cond_wait()
执行了执行虚假唤醒的选项,返回 0。这本身不是错误。
我认为260甚至超出了系统错误的范围。数字 260 与定义的系统错误编号范围的关系是完全不相关的。
errno
的值仅在函数调用返回失败代码后立即传达有用信息,并且仅适用于记录为在错误时设置
errno
的函数。 pthread_cond_wait
不是这些函数之一 - 相反,它是返回值 is错误号的函数之一。 那么这在 Linux 和 MacOS 中实际上是如何工作的呢?
在 Linux您应该解释 Linux signal(7) 手册页以表明
上,被信号中断后,如果使用 pthread_cond_wait()
标志注册了处理程序,则
SA_RESTART
将自动重新启动,否则它将自动重新启动。返回给它的调用者。如果您愿意,您可以将“因错误 EINTR
失败”与 pthread_cond_signal()
的记录行为进行协调,将前者视为抽象规范,在 pthread_cond_wait()
的异常情况下实现为返回 0。或者你可以在这个细节中将 signal(7) 算作错误。对于 MacOS,您自己的实验表明 pthread_cond_wait()
在被信号中断后返回 0。其他情况下,该功能可能会自动重启。