Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ linux pthreads上的gcc 4.7-使用uuu线程的非平凡线程本地解决方案(无boost)_C++_Linux_Multithreading_C++11_Pthreads - Fatal编程技术网

C++ linux pthreads上的gcc 4.7-使用uuu线程的非平凡线程本地解决方案(无boost)

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;

在C++11中,可以使用线程\本地存储的非平凡对象:

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(){cout
pthread\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();
    }