带有GCC的C++11中的线程范围对象

Thread-scoped objects in C++11 with GCC

本文关键字:范围 对象 线程 C++11 GCC 带有      更新时间:2023-10-16

考虑以下C++11程序:

struct S {
   S() {/* do something */ }
} global_object;
int main() {
}

我还没有GCC 4.8要测试,但从我读到的关于C++11标准的内容来看,无论我是否将全局对象声明为thread_local,对象本身都将为程序执行期间可以创建的所有可能线程实例化一次。

GCC中是否有一种方法(可移植或不可移植)可以在每次一个线程启动时实例化和约束全局对象,并在每次同一线程结束时销毁全局对象?

但从我读到的关于C++11标准的内容来看,无论我是否将全局对象声明为thread_local,对于程序执行过程中可以创建的所有可能的线程,对象本身都会实例化一次

这不是C++11标准所说的。C++11标准(草案n3337)的相关章节:

  • 3.7.2线程存储时间,第1条:

所有用thread_local关键字声明的变量都具有线程存储持续时间。这些实体的存储应在创建它们的线程期间持续每个线程都有一个不同的对象或引用,使用声明的名称是指与当前线程关联的实体。

  • 7.1.1存储类别说明符,第4条:

thread_local说明符表示命名实体具有线程存储持续时间(3.7.2)。它应仅应用于命名空间或块作用域的变量名称以及静态数据成员的名称当thread_local应用于块作用域的变量时,如果存储类说明符static没有显式显示,则它是隐含的。

它没有指出,如果在全局命名空间中用thread_local定义了一个对象,那么只会创建它的一个实例。Jesse Good已经发布的另一个例子打印了全局对象的每个实例的唯一地址(见在线演示):

#include <iostream>
#include <thread>
#include <vector>
struct S {};
thread_local S global_s;
int main()
{
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i)
        threads.push_back(std::thread([](){ std::cout << &global_s << 'n'; }));
    for (auto& t: threads) t.join();
}

输出:

0x4165993f0x4205a93f0x4485e93f0x42a5b93f0x4525f93f0x45c6093f0x4666193f0x4706293f0x43e5d93f0x4345c93f

无论我是否将全局对象声明为thread_local

你试过了吗?我非常确信它为每个线程创建一个单独的实例。

请参阅coliru上的以下代码:

struct S {
   int i = 0;
   S() {}
};
thread_local S global;
int main()
{
    std::thread t1([](){global.i = 1; std::cout << global.i << std::endl;});
    t1.join();
    std::cout << global.i << std::endl;
    std::thread t2([](){global.i = 2; std::cout << global.i << std::endl;});
    t2.join();
    std::cout << global.i << std::endl;
    std::thread t3([](){global.i = 3; std::cout << global.i << std::endl;});
    t3.join();
    std::cout << global.i << std::endl;
}

它输出:

1
0
2
0
3
0