【问题标题】:Why is a static thread_local object in C++ constructed twice?为什么 C++ 中的静态 thread_local 对象构造了两次?
【发布时间】:2017-11-10 15:48:52
【问题描述】:

这段代码:

#include <iostream>
#include <thread>
#include <mutex>

struct Singl{
    Singl(Singl const&) = delete;
    Singl(Singl&&) = delete;

    inline static thread_local bool alive = true;

    Singl(){
        std::cout << "Singl() " << std::this_thread::get_id() << std::endl;
    }
    ~Singl(){
        std::cout << "~Singl() " << std::this_thread::get_id() << std::endl;
        alive = false;
    }
};

static auto& singl(){
    static thread_local Singl i;
    return i;
}

struct URef{
    ~URef(){
        const bool alive = singl().alive;
        std::cout << alive << std::endl;
    }
};


int main() {
    std::thread([](){
        singl();
        static thread_local URef u;
    }).join();

    return 0;
}

有以下输出:

Singl() 2
Singl() 2
1
~Singl() 2
~Singl() 2

我正在使用 mingw-w64 gcc7.2 POSIX 线程在 Windows 下编译和运行。

Coliru 有不同的输出: http://coliru.stacked-crooked.com/a/3da415345ea6c2ee

这是什么?我的工具链/编译器有问题,还是应该这样?为什么我在同一个线程上有两个 thread_local 对象(或构造了两次?)?

【问题讨论】:

  • 我建议在调试器中运行它,在Singl 构造函数中放置一个断点,并在每次遇到断点时查看堆栈跟踪。这应该会给你一个关于发生了什么的线索。
  • 已经完成 - 不知道......所有 mingw-w64 gcc 7.x 的行为相同。 VS2017 的输出与 coliru 相同。
  • @tower120 那么堆栈跟踪是什么样的?
  • FWIW VS2015 只构造一次Singl
  • 在 ~URef() 中构造的第二个 Singl,constor 本身由神秘的 TLS 包装器 __tls_init 调用。然后两个析构函数都调用线程销毁。

标签: c++ gcc thread-safety mingw-w64 thread-local-storage


【解决方案1】:

可能是你的编译器或工具链有问题。

在 Linux 上使用 clang++ 8 和 g++ 8.2(确切地说是 Devuan ASCII),线程局部变量只构造一次。

【讨论】:

  • 是的,你是对的——那是 mingw 的错。我已经回答了我自己的问题。
猜你喜欢
  • 1970-01-01
  • 2016-02-11
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 2011-01-02
  • 1970-01-01
  • 2012-09-25
  • 2021-04-20
相关资源
最近更新 更多