首页 > 解决方案 > 静态成员和分离线程本身的释放顺序

问题描述

有一个全局函数可以初始化和清理一些资源。
但是当没有其他线程正在运行时,必须调用这两个函数。(如curl_global_init
必须手动调用初始化程序,但我不希望手动调用清洁器。
所以我做了以下。

class GLOBAL_WRAPPER {
 public:
  static void init() {
    getInstance();
  }

  static GLOBAL_WRAPPER& getInstance() {
    static GLOBAL_WRAPPER inst;
    return inst;
  }

 private:
  GLOBAL_WRAPPER() {
    // do global init call
  }
  ~GLOBAL_WRAPPER() {
    // do global cleanup call
  }
};

void GLOBAL_INIT() {
  GLOBAL_WRAPPER::init();
}



int main(){
  GLOBAL_INIT();

  // do whatever you want

  // std::thread([](){for(;;);}).detach(); oops!
}

但是在这种糟糕的情况下,比如:创建分离的线程而不是在结束之前终止它main,什么时候调用静态变量的释放(GLOBAL_WRAPPER在这种情况下)?

  1. 分离的线程被终止并且静态变量被释放
  2. 释放静态变量并终止分离的线程
  3. 实现定义。

我只对线程本身感兴趣,而不是线程存储持续时间对象。

标签: c++libcurl

解决方案


C++ 标准规定(用很多话来说)返回 frommain等同于调用std::exit.

主要功能 [basic.start.main]

main 中的 return 语句具有离开 main 函数(销毁具有自动存储持续时间的任何对象)并以返回值作为参数调用 std::exit 的效果。如果控制从 main 的复合语句的末尾流出,则效果等同于操作数为 0 的返回。

exit定义如下(无关细节省略):

启动和终止 [support.start.term]

[[noreturn]] 无效退出(int 状态);

效果:

— 首先,销毁具有线程存储持续时间并与当前线程关联的对象。接下来,销毁具有静态存储持续时间的对象,并调用通过调用 atexit 注册的函数。

— 接下来,所有打开的 C 流……都被删除。

— 最后,控制权返回到宿主环境。如果状态为零或 EXIT_SUCCESS,则返回状态成功终止的实现定义形式。如果状态为 EXIT_FAILURE,则返回状态不成功终止的实现定义形式。

没有定义当主执行线程返回时,如果非主执行线程正在运行会发生什么。所示代码不保证非主执行线程在main返回之前终止/排序。

因此,该标准唯一规定的是:

  1. 全局对象被销毁

  2. “控制权返回宿主环境”,又名:“它死了,吉姆”。

该标准没有定义当主执行线程返回时非主执行线程正在运行时会发生什么。又名:未定义的行为。


推荐阅读