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

时间:2013-07-04 13:26:24

标签: c++ gcc c++11 g++

考虑以下C ++ 11程序:

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

int main() {
}

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

GCC中是否存在一种方法(可移植或不可移植),每次一个线程启动时都会实例化并构造全局对象,并且每次相同的线程完成时都会被破坏?

2 个答案:

答案 0 :(得分:4)

  

但是从我读到的关于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应用于块作用域的变量时,隐含存储类指定符静态如果它没有明确显示。

如果在全局命名空间中使用thread_local定义了一个对象,则只会创建一个实例。由Jesse Good发布的替代示例打印全局对象的每个实例的唯一地址(请参阅online demo):

#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();
}

输出:

0x4165993f
0x4205a93f
0x4485e93f
0x42a5b93f
0x4525f93f
0x45c6093f
0x4666193f
0x4706293f
0x43e5d93f
0x4345c93f

答案 1 :(得分:3)

  

无论我是否将全局对象声明为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