thread_local 变量在线程内不一致

joh*_*ohn 5 c++ multithreading thread-local

我在文件 tracker.hpp 中有一个变量:

namespace TRIALS
{
    static thread_local int a = -1;
}
Run Code Online (Sandbox Code Playgroud)

我在 ema.hpp/ema.cpp 中的文件中有另一个名为 EMP 的类

namespace Algo
{
    class EMP
    {
        public:
            void Sample();
    };
}
Run Code Online (Sandbox Code Playgroud)
namespace Algo
{
    void EMP::Sample()
    {
        std::cout << "model " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我的主文件


auto model = Algo::EMP();

void Simulate(const int a)
{
    TRIALS::a = a;
    model.Sample()
    std::cout << "worker " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;
}

int main()
{
    std::cout << &TRIALS::a << std::endl;
    const int nthreads = 1;

    std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;

    std::vector<std::thread> threads;
    for(int i=0; i<nthreads; ++i)
    {
        threads.emplace_back(&Simulate, i);
    }

    for(auto &thread : threads)
    {
        thread.join();
    }

    std::cout << "main " << std::this_thread::get_id() << " " << &TRIALS::a << " " << TRIALS::a << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我只是运行一个线程进行调试,但这是输出:

0x7f9540b621d8

main 140279012532800 0x7f9540b621d8 -1 (如预期)

型号 140278985606912 0x7f953f1b469c -1 (这不应该是0吗?)

工人 140278985606912 0x7f953f1b4698 0 (如预期)

main 140279012532800 0x7f9540b621d8 -1 (如预期)

我的印象是每个线程都有它自己的 TRIALS::a 本地副本。模型中的 a 正确地递增,但是当它从同一线程中的函数返回时,该值仍然为 0。我正在打印线程 id 和 a 的地址以进行良好的测量,我发现实际上有 3 个不同的值尽管只有两个线程,但 TRIALS::a 的版本。

static thread_local int a作为一个额外问题,和之间有什么区别thread_local int a

Max*_*kin 8

在您的示例中,static使该thread_local对象使用内部链接,以便每个翻译单元(.cpp 文件)都有自己的变量副本。

有关详细信息,请参阅存储类说明符:

thread_local关键字仅适用于在命名空间范围内声明的对象、在块范围内声明的对象以及静态数据成员。表明该对象具有线程存储持续时间。它可以与staticextern结合使用,分别指定内部或外部链接(除了始终具有外部链接的静态数据成员),但附加的静态不会影响存储持续时间。

也就是说,您可能想删除该static关键字,以便在整个应用程序中只有该对象的一份副本。在头文件中执行:

namespace TRIALS {
    extern thread_local int a;
}
Run Code Online (Sandbox Code Playgroud)

并在其中之一.cpp

thread_local int TRIALS::a = -1;
Run Code Online (Sandbox Code Playgroud)

在 C++17 中,您可以创建变量inline以避免必须在 a 中提供其定义.cpp

namespace TRIALS {
    inline thread_local int a = -1;
}
Run Code Online (Sandbox Code Playgroud)