具有与 std::thread 不同的线程库的 C++ thread_local

Posted

技术标签:

【中文标题】具有与 std::thread 不同的线程库的 C++ thread_local【英文标题】:C++ thread_local with different threading library than std::thread 【发布时间】:2018-01-29 10:24:26 【问题描述】:

C++11 有关键字thread_local。我想知道这个关键字是否只适用于使用标准库(std::thread)创建的线程,或者它保证可以与其他线程库一起使用,例如Windows CreateThread 函数或 Unix pthread。

Microsoft documentation for visual studio 声明:

线程扩展存储类修饰符用于声明线程局部变量。对于 C++11 及更高版本中的可移植等效项,请将 thread_local 存储类说明符用于可移植代码。在 Windows 上,thread_local 使用 __declspec(thread) 实现。

因此 thread_local 在 MS Visual Studio 中按预期工作。我仍然想知道其他编译器和平台的情况是否如此。

【问题讨论】:

最有可能依赖于实现。 这可能是UB。但它真的有效吗?可能,只要库使用内核线程。但你不应该依赖其中任何一个。 @freakish:我不会这么认为。例如,std::thread ctor 可能会在内核线程中初始化线程本地存储。它适用于 Windows,因为内核线程有 TlsGetValue/TlsSetValue 【参考方案1】:

C++ 标准在[intro.multithread]/1 处定义如下线程:

执行线程(也称为线程)是一个单一的流程 程序中的控制,包括初始调用 特定的***函数,并递归地包含每个函数 调用随后由线程执行。 [ 注:当一个 线程创建另一个,对顶层函数的初始调用 新线程由新线程执行,而不是由创建 线。 — 尾注 ] 程序中的每个线程都可能访问 程序中的每个对象和函数。在托管下 实现,一个 C++ 程序可以运行多个线程 同时。每个线程的执行都按照 本国际标准的其余部分。整个执行 程序由其所有线程的执行组成。 [ 笔记: 通常,执行可以看作是所有它的交错 线程。但是,某些种类的原子操作,例如,允许 执行与简单交错不一致,如所述 以下。 — 尾注 ] 在独立实现下,它是 实现定义一个程序是否可以有多个线程 执行。

请注意,以上内容完全不限于std::thread 创建的线程。此外,该标准甚至承认存在 至少一个 不一定由std::thread 创建的执行线程,在[intro.progress]/8:

实现创建的线程是否由实现定义 执行 main 和创建的执行线程 通过 std​::​thread 提供并发前向进度保证。 [ 注意:鼓励通用实现提供 这些保证。 — 尾注 ]

此外,虽然以下内容是注释,不能被视为规范,但阅读[thread.threads]/1 仍然令人鼓舞:

[thread.threads] 描述了可用于创建和 管理线程。 [ 注意:这些线程旨在一对一映射 与操作系统线程。  — 尾注 ]

这对我来说都表明任何thread_local 存储都可以在任何符合上述定义的“执行线程”中使用,无论它是由std::thread 创建的还是由某种实现定义的方式创建的。我不希望一个理智的托管实现会有其他行为。

【讨论】:

这是一个建议,而不是一个具体的陈述。 @DavidHaim - 什么?那个笔记?我知道,因此我称之为非规范。然而,其他一切都是规范的。 我的意思是该标准可能暗示它可能会起作用,但该标准并没有真正明确说明。在我看来,你的回答肯定表明这一点。 @DavidHaim - 我的回答表明该标准定义了一个执行线程,但没有指定必须如何创建。是的,thread_local 存储的行为在执行线程中得到了很好的定义,无论是如何创建的。如果实现提供了更多的方法来创建符合标准定义的线程,那么这些线程中的任何thread_local 存储都将按照标准的规定运行。 线程是否映射到 OS 线程(这到底意味着什么,内核调度的线程?还是 OS API 线程?)并不重要,但它们是否映射到同一事物。例如,thread_local 是否可以与使用 Win32 API 创建的线程一起正常工作。由于该标准没有提及与这些特定于平台的功能的关系,因此这些似乎是浑水。问题是,即使我们同意它可以与 OS API 线程一起使用,也有第三方线程库。似乎不可能保证他们都是“乖巧”的thread_local

以上是关于具有与 std::thread 不同的线程库的 C++ thread_local的主要内容,如果未能解决你的问题,请参考以下文章

C ++中std :: thread优于pthread的优势[重复]

C/C++:std::thread构造函数死锁问题:WIN32下不可以在DllMain中创建线程

std::async的使用总结

C++11 的 std::thread 是不是与 POSIX 信号量兼容?

c++11的std::thread能用类的成员函数构造一个线程吗?语法怎样?

cpp►C++11标准线程库<thread>