在C ++ 11中,您可以使用带有thread_local存储的非平凡对象:
class X { ... } void f() { thread_local X x = ...; ... }
不幸的是,此功能尚未在gcc中实现(从4.7开始)。
gcc确实允许您拥有线程局部变量,但仅具有普通类型。
我正在寻找一种解决方法:
这是我到目前为止的内容:
#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可能就是我想要的:
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清理函数:
boost::thread_specific_ptr
pthread_key_create
destructor
http://pubs.opengroup.org/onlinepubs/009696799/functions/pthread_key_create.html
目前尚不清楚这两种方法之间的区别(如果有)。?
正如迈克所说pthread_cleanup_push的不合适。正确的方法是使用pthread_key_create。
我已经实现了一个小型演示程序,以演示如何执行此操作。我们实现thread_local您使用的宏,如下所示:
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。
__thread
概述:
std::aligned_storage
pthread_setspecific
…
#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); x.f(); } int main() { thread t(g); t.join(); }
笔记: