C ++ 11:非平凡线程局部静态变量?

时间:2012-08-21 05:52:21

标签: c++ multithreading c++11 thread-local thread-local-storage

我有一个班级X:

class X { ... }

我想这样做:

void f()
{
    thread_local static X x = ...;

    ...
}

(实际上我正在使用gcc,因此关键字是“__thread”)

但我不能,因为你只能有琐碎的thread_locals。

最好的解决办法是什么?

如果我这样做:

void f()
{
    thread_local static X* p = 0;

    if (!p)
       p = new X(...);

    X& x = *p;

    ...
}

然后:

  1. 线程退出时不会调用析构函数
  2. 不必要的动态内存分配。
  3. 更新

    这是我到目前为止所做的:

    #include <iostream>
    #include <type_traits>
    
    using namespace std;
    
    class X { public: X() { cout << "X::X()" << endl; }; ~X() { cout << "X::~X()" << endl; } };
    
    void f()
    {
            static __thread bool x_allocated = false;
            static __thread aligned_storage<sizeof(X),
                 alignment_of<X>::value>::type x_storage;
    
            if (!x_allocated)
            {
                    new (&x_storage) X;
                    x_allocated = true;
                    // add thread cleanup that calls destructor
            }
    
            X& x = *((X*) &x_storage);
    }
    
    int main()
    {
            f();
    }
    

    这解决了动态内存分配问题。我只需要添加线程清理处理程序。有没有机制用pthreads做到这一点?

2 个答案:

答案 0 :(得分:6)

标准将thread_local描述为与第7.1.1节中的其他(staticextern等)一样的存储说明符。通过该单词的任何定义,对“简单”数据类型没有限制。

pre-C++11 discussion document N2147中简要讨论了该问题(参见“线程变量动态初始化”一节)。这包括对正确实施中涉及的关键问题的描述。显然GCC实现(static __thread)还没有解决这些问题(这与GCC没有正式支持C ++ 11 thread_local)这一事实是一致的。

另一种选择是boost::thread_specfic_ptr<>提及in this earlier post并描述here

另一种方法是使用std::thread对象来实现线程,并确保每个实例都维护自己的变量副本,可能包含在unique_ptr中。

答案 1 :(得分:6)

事实上,

thread_local__thread并不是一回事。它们之间的主要区别正是您偶然发现的那个 - thread_local允许变量为非POD。不幸的是,这也有性能影响。有关这些性能影响的详细信息,请参阅this question