C++ linux pthreads上的gcc 4.7-使用uuu线程的非平凡线程本地解决方案(无boost)
在C++11中,可以使用线程\本地存储的非平凡对象:C++ linux pthreads上的gcc 4.7-使用uuu线程的非平凡线程本地解决方案(无boost),c++,linux,multithreading,c++11,pthreads,C++,Linux,Multithreading,C++11,Pthreads,在C++11中,可以使用线程\本地存储的非平凡对象: class X { ... } void f() { thread_local X x = ...; ... } 不幸的是,这个特性还没有在gcc中实现(从4.7开始) gcc允许您拥有线程局部变量,但只允许使用普通类型 我正在寻找解决办法: 以下是我到目前为止的情况: #include <iostream> #include <type_traits> using namespace std;
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();
}
#包括
#包括
使用名称空间std;
X类
{
公众:
X(){coutpthread\u key\u create
和friends是您希望使用析构函数实现类型的线程特定变量。但是,这些通常需要您管理创建和销毁变量的整个过程,我不确定您是否可以将它们与\u thread
结合使用
pthread\u cleanup\u push
不适用。它旨在允许在(短)时间内线程退出时释放资源使用该资源的代码块;如您链接到的文档中所述,它必须由该函数的同一级别的pthread\u cleanup\u pop
匹配,如果线程从其主函数返回,则不会调用处理程序。这意味着,如果希望线程局部变量在c调用函数
为了不禁止第三方库的用户,提供了一种方便、便携的方法来管理线程本地存储。正如Mike所说的pthread\u cleanup\u push
是不合适的。正确的方法是使用pthread\u key\u create
我已经实现了一个小的演示程序来演示如何实现它。我们实现了一个宏thread\u local
,您可以这样使用它:
使用真正的C++11功能,它将是:
void f()
{
thread_local X x(1,2,3);
...
}
这是:
void f()
{
thread_local (X, x, 1, 2, 3);
...
}
这与boost::thread_specific_ptr的区别在于,动态内存分配为零。所有内容都以\uu thread
持续时间存储。它的重量也明显较轻,但它是特定于gcc/linux的
概述:
我们使用std::aligned_storage
为变量创建线程持续时间空间
在给定线程的第一个条目中,我们使用placement new在存储器中构造变量
我们还为placement delete调用分配一个链表条目
我们使用pthread_setspecific
跟踪每个线程列表头
传递给pthread\u key\u create
的函数在线程退出时遍历调用placement deletes的列表
#包括
#包括
使用名称空间std;
静态pthread_key_t key;
静态pthread_once_t once_control=pthread_once_INIT;
结构析构函数列表
{
无效(*析构函数)(无效*);
void*param;
析构函数列表*下一步;
};
静态void执行析构函数列表(void*v)
{
对于(析构函数列表*p=(析构函数列表*)v;p!=0;p=p->next)
p->析构函数(p->param);
}
静态无效创建_键()
{
pthread_key_create(&key,execute_destructor_list);
}
void add_析构函数(析构函数列表*p)
{
pthread_once(&once_控件,创建_键);
p->next=(析构函数列表*)pthread\u getspecific(键);
pthread_setspecific(键,p);
}
模板静态无效位置_delete(void*t){((t*)t)->~t();}
#定义线程\u本地(T,T,…)\
T&T=*((T*)\
({ \
typedef typename对齐_存储::类型存储\
静态u_线程bool allocated=false\
静态线程存储\
静态线程析构函数列表\
\
如果(!已分配)\
{ \
新(和存储)T(uu VA_ARGS_uu)\
分配=真\
dlist.destructor=placement\u delete\
dlist.param=&storage\
添加析构函数(&D列表)\
} \
\
&储存\
}));
X类
{
公众:
int i;
X(int i_in){i=i_in;可能会有帮助。@MikeSeymour:请参阅标题的最后两个词。:)在任何情况下,boost::thread_specific_ptr都需要动态内存分配-而在上述解决方案中,存储是u thread allocated的。@MikeSeymour:事实上我撒谎了,你可以使用显式线程特定的(void(*cleanu function)(T*))
在上述调用placement_delete_x的解决方案中。但是,唉,我不能使用boost。boost::thread_specific_ptr使用什么机制来调用清理处理程序?(我想我可以吃掉源代码并找出答案)抱歉,我没有发现你的奇怪禁令。我将在这里留下评论,因为它可能对那些能够使用有用的第三方库的人有所帮助。我想它会在POSIX平台上使用pthread\u cleanup\u push
,但你必须查看源代码才能确定。@MikeSeymour:不确定这有多奇怪,大多数boost库包括根据Google的编码准则,不允许使用ding boost线程:例如。对不起,为什么不能将pthread\u key\u create
与\u thread
结合使用?线程退出时调用pthread\u key\u create
的析构函数参数acement\u delete\u x
对吗?实际上,我不确定;我对\u线程
的细节了解不够,不知道你是否可以在它和pthreads
之间拼凑出某种混合。我会调整答案。我已经让它工作了,非常简单。\u线程
ju
#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();
}