gcc 4.7在Linux pthreads – 非常规thread_local解决方法使用__thread(没有提升)

在C ++ 11中,可以使用thread_local存储来创build一个非平凡的对象:

class X { ... } void f() { thread_local X x = ...; ... } 

不幸的是,这个function还没有在gcc中实现(从4.7开始)。

海湾合作委员会确实允许你有线程局部variables,但只有琐碎的types。

我正在寻找一个解决方法:

这是我到目前为止:

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

我需要帮助的是在当前线程退出时调用placement_delete_x(&x_storage)。 有没有一种机制在pthreads和/或linux我可以用来做到这一点? 我需要添加一个函数指针和一个参数的某种pthread清理堆栈?

更新:

我认为pthread_cleanup_push可能是我想要的:

http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_cleanup_push.3.html

这是否会在正确的情况下调用清理处理程序?

更新2:

它看起来像boost::thread_specific_ptr最终调用pthread_key_create destructor参数,而不是pthread_cleanup_push – 调用它的tls清理function:

http://pubs.opengroup.org/onlinepubs/009696799/functions/pthread_key_create.html

目前还不清楚这两种方法之间有什么区别,如果有的话。 ?

pthread_key_create和朋友是你想要使用析构函数实现线程特定的类型变量。 但是,这些通常需要您管理创建和销毁变量的整个过程,我不确定是否可以将它们与__thread结合使用。

pthread_cleanup_push不适合。 如果线程在使用该资源的(短)代码块期间退出,则允许释放资源; 如链接到的文档中所述,它必须与该函数的同一级别的pthread_cleanup_pop匹配,并且如果线程从其主函数返回,则不会调用该处理程序。 这意味着如果你希望线程局部变量在对函数的调用之间保持不变,就不能使用它。

对于那些不禁止使用第三方库的人来说, Boost提供了一种便捷的方式来管理线程本地存储。

正如Mike所说, pthread_cleanup_push不合适。 正确的方法是使用pthread_key_create

我已经实现了一个小的演示程序来演示如何做到这一点。 我们实现一个像这样使用的宏thread_local

有了真正的C ++ 11功能,它将是:

 void f() { thread_local X x(1,2,3); ... } 

这是它:

 void f() { thread_local (X, x, 1, 2, 3); ... } 

这个和boost :: thread_specifc_ptr之间的区别在于没有动态内存分配。 所有内容都以__thread持续时间存储。 它也明显更轻,但它是特定于gcc / linux的。

概述:

  1. 我们使用std::aligned_storage为变量创建__thread持续时间空间
  2. 在给定线程的第一个条目中,我们使用placement new来构造存储中的变量
  3. 我们还__thread分配一个链接列表条目的位置删除调用
  4. 我们使用pthread_setspecific来跟踪每个线程列表头
  5. 传递给pthread_key_create的函数pthread_key_create线程退出时调用位置的列表。

 #include <iostream> #include <thread> using namespace std; static pthread_key_t key; static pthread_once_t once_control = PTHREAD_ONCE_INIT; struct destructor_list { void (*destructor)(void*); void* param; destructor_list* next; }; static void execute_destructor_list(void* v) { for (destructor_list* p = (destructor_list*) v; p != 0; p = p->next) p->destructor(p->param); } static void create_key() { pthread_key_create(&key, execute_destructor_list); } void add_destructor(destructor_list* p) { pthread_once(&once_control, create_key); p->next = (destructor_list*) pthread_getspecific(key); pthread_setspecific(key, p); } template<class T> static void placement_delete(void* t) { ((T*)t)->~T(); } #define thread_local(T, t, ...) \ T& t = *((T*) \ ({ \ typedef typename aligned_storage<sizeof(T), \ alignment_of<T>::value>::type Storage; \ static __thread bool allocated = false; \ static __thread Storage storage; \ static __thread destructor_list dlist; \ \ if (!allocated) \ { \ new (&storage) T(__VA_ARGS__); \ allocated = true; \ dlist.destructor = placement_delete<T>; \ dlist.param = &storage; \ add_destructor(&dlist); \ } \ \ &storage; \ })); class X { public: int i; X(int i_in) { i = i_in; cout << "X::X()" << endl; }; void f() { cout << "X::f()" << endl; } ~X() { cout << "X::~X() i = " << i << endl; } }; void g() { thread_local(X, x, 1234); xf(); } int main() { thread t(g); t.join(); } 

笔记:

  1. 您需要为每个pthread_ *调用添加错误检查。 我刚刚删除它的说明。
  2. 它使用__thread这是一个GNU扩展
  3. 它使用表达式语句将辅助__thread变量名称保留在父范围之外。 这也是一个GNU扩展。