在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的。
概述:
std::aligned_storage
为变量创建__thread持续时间空间 __thread
分配一个链接列表条目的位置删除调用 pthread_setspecific
来跟踪每个线程列表头 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(); }
笔记:
__thread
这是一个GNU扩展