-4

atexit打电话合法pthread_exit吗?没有它,main()返回时所有线程都将终止。(简单的解决方案是修改main()为调用pthread_exit()自身,但在这个最小示例派生的实例中这是不可能的)。

#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <pthread.h>

void *foo(void *data) {
  for (int i = 0; i < 10; ++i) {
    std::cout << i << "\n";
    sleep(1);
  }
  return NULL;
}

void foo_init() {
  std::atexit([](){
    pthread_exit(NULL);
  });
}

int main() {
  foo_init();
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  pthread_t thr;
  pthread_create(&thr, &attr, foo, NULL);
}

状态的联机帮助页pthread_exit

线程终止不会释放任何应用程序可见的进程资源,包括但不限于互斥锁和文件描述符,也不会执行任何进程级别的清理操作,包括但不限于调用任何可能存在的 atexit() 例程。

这似乎排除了疯狂递归破坏事物的风险。

它还指出:

如果从作为对 pthread_exit() 的隐式或显式调用的结果而调用的取消清理处理程序或析构函数调用 pthread_exit() 的行为是未定义的。

这表明在某些地方调用 是未定义的pthread_exit,但是(除非 main 需要 > 10 秒才能返回,让我们假设在“真实”情况下是不可能的)不适用。

这个例子“对我有用”但是 POSIX 需要它工作吗?如果不是,它是未定义的还是未指定的?

4

1 回答 1

4

就 POSIX 而言,存在一些问题:

  • 文档pthread_exit()说:“在最后一个线程终止后,进程以退出状态 0 退出。行为就像在线程终止时调用 exit() 的参数为零”
  • 文档exit()说,“如果通过调用 atexit() 注册的函数未能返回,则不应调用剩余的注册函数,并且不应完成其余的 exit() 处理。如果调用 exit() 更多不止一次,行为是未定义的”。

所以严格来说,当pthread_exit()最后一个线程被调用时,其行为就好像exit()被调用了不止一次,也就是说它是未定义的行为。

也就是说,我想最糟糕的情况是应用程序在最后一个线程退出时会崩溃或死锁。由于该过程无论如何都会退出,因此风险可能是可以接受的,具体取决于您的应用程序的性质以及您的测试表明风险可能有多低。

如果您可以安排知道哪个线程将是最后一个退出,我认为您可以在atexit()回调中阻塞信号量、条件变量或互斥锁,而不是调用pthread_exit(). 当它即将调用pthread_exit()(或返回)时,让最后一个线程释放该块。

于 2012-08-14T15:02:42.443 回答