【问题标题】:Using atexit to call pthread_exit使用 atexit 调用 pthread_exit
【发布时间】:2012-08-10 20:12:58
【问题描述】:

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 要求它工作?如果不是,是未定义还是未指定?

【问题讨论】:

    标签: c++ pthreads posix language-lawyer


    【解决方案1】:

    就POSIX而言存在一些问题:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多