【问题标题】:pthread: join a detached thread doesn't set errno correctlypthread:加入一个分离的线程没有正确设置 errno
【发布时间】:2012-12-17 16:23:54
【问题描述】:

我正在检查“pthread_join”的行为并有以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>

#include <pthread.h>

void *thread(void *vargp)
{
    pthread_detach(pthread_self());
    pthread_exit((void *)42);
}

int main()
{
    int i = 1;
    pthread_t tid;

    pthread_create(&tid, NULL, thread, NULL);

    sleep(1);
    pthread_join(tid, (void **)&i);
    printf("%d\n", i);
    printf("%d\n", errno);
}

在我的平台上观察到的输出(Linux 3.2.0-32-generic #51-Ubuntu SMP x86_64 GNU/Linux):

  1. 注释掉了“sleep(1)”: 42 0

  2. 使用 sleep 语句,它会产生: 1 0

根据 pthread_join 的手册页,当我们尝试加入不可加入的线程时,我们应该得到错误“EINVAL”,但是,上述两种情况都没有设置 errno。而且在第一种情况下,似乎我们甚至可以获得分离线程的退出状态,我对结果感到困惑。谁能解释一下?谢谢

[编辑]:我意识到第一个 printf 可能会重置 'errno',但是,即使我交换了两个 'printf' 语句的顺序,我仍然得到相同的结果。

【问题讨论】:

  • 您描述的情况是POSIX允许的。也许手册页已经过时了。 (PS。我的意思是案例 1)。
  • 同时知道这两种情况下调用pthread_detach() 的结果也会很有趣。
  • 对于使用 Debian(稳定)的案例 2,我收到了 errno==EINVAL
  • @chill 您对此声明有任何引用吗?
  • @alk 您是说在情况 1 中您也无法设置 errno 吗?这更令人困惑:(我认为我们需要有人指导我们一些权威/官方的 POSIX pthread 规范。

标签: c pthreads pthread-join


【解决方案1】:

你的期望是错误的。在分离的线程上调用 pthread_join 会调用未定义的行为。不需要设置errno,也不需要返回错误码,甚至根本不需要返回。

如果您需要引用,

如果 pthread_join() 的线程参数指定的值不引用可连接线程,则行为未定义。

来源:http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html

另外,请注意大多数 pthread 函数,包括 pthread_join,不使用 errno。相反,它们将错误代码作为返回值返回。因此,在调用 pthread 函数后检查 errno 是错误的,即使您在调用它时没有调用未定义的行为。

【讨论】:

  • 我的手册页与此链接中完全相同:kernel.org/doc/man-pages/online/pages/man3/pthread_join.3.html 是否已过时?我在哪里可以获得最新/正确的?
  • 我会说 Linux 手册页只是模棱两可,并非完全错误或过时。在描述的第一段中,它说:“thread 指定的线程必须是可连接的。”这与说“如果线程不可连接,则会导致错误”不同。但是,即使它说的是后者,您仍然无法安全地进行调用,因为 任何 对已退出的分离线程使用 pthread_t 值会调用未定义的行为。
  • 不过,我同意应该改进 Linux 手册页,使其更加清晰。部分问题源于 POSIX 先前版本中的一个错误,该错误列出了许多 pthread 函数的无意义错误返回,除非已经调用了未定义的行为(在这种情况下,关于不需要遵循错误)。这在规范中被报告为一个错误,并在 POSIX 2008 中得到修复。您将在我链接的页面中看到,在最底部,有关已删除错误错误的文本。
【解决方案2】:

你通过读取函数pthread_join的返回值得到这个错误,试试这个:

if (errno = pthread_join(tid,NULL)) {
    printf("An error ocurred: %i", errno);
}

【讨论】:

  • 通过获取返回值,我仍然将 'errno' 设为 0。看来 pthread_join 调用被认为是成功的。
  • 最好:int result = pthread_join(...; if (result) printf(..., result);
  • 它仍然无效,因为 OP 正在调用 UB 试图加入一个分离(和终止)的线程。顺便说一句,可能永远不需要检查 pthread_join 的返回值,因为唯一的失败是 UB 或编程错误,而不是环境/运行时错误。
猜你喜欢
  • 1970-01-01
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 2020-09-02
相关资源
最近更新 更多