小编典典
正如迈克所说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持续时间空间
从给定线程的第一个条目开始,我们使用placement new在存储中构造变量
我们还__thread为展示位置删除调用分配了一个链接列表条目
我们pthread_setspecific用来跟踪每个线程的列表头
传递给该函数的函数pthread_key_create会在线程退出时删除调用放置的列表。
…
#include
#include
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 static void placement_delete(void* t) { ((T*)t)->~T(); }
#define thread_local(T, t, ...) \
T& t = *((T*) \
({ \
typedef typename aligned_storage
alignment_of::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; \
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();
}
笔记:
您需要为每个pthread_ *调用添加错误检查。我只是将其删除以进行说明。
它使用__thread哪个是GNU扩展
它使用 表达式语句 将辅助__thread变量名称保留在父作用域之外。这也是GNU扩展。
2020-06-03