C++线程局部存储(TLS)

来源:互联网 发布:macbook下软件好下吗 编辑:程序博客网 时间:2024/06/09 19:38

基本类型(如(unsigned) int,long, char,指针,c类型的结构体等 )可以采用用 __thread修饰符来定义线程局部变量.
示例如下:

__thread int i;extern __thread struct state s;static __thread char *p;

像 string 等类是不能直接用 __thread 修符的,只能用其指针类型的.即:

1
__thread std::string *  p_thread_name;

使用 __thread修饰符来定义一些类的线程局部变量,往往容易造成内存泄漏.

网上实现的Tls类,可以方便用户使用!

头文件:

//Tls.h#ifndef __SAP_UTIL_TLS_H_#define __SAP_UTIL_TLS_H_#include <pthread.h> class Tls{public:    static int pthread_atexit_add(void *arg, void (*free_fn)(void *) );    static int pthread_atexit_remove(void *arg, void (*free_fn)(void*) );protected:    static void pthread_atexit_done(void *arg);    static void pthread_atexit_init(void);protected:    static pthread_key_t    _pthread_atexit_key;    static pthread_once_t   _pthread_atexit_control_once;}; #endif
实现文件:

// Tls.cpp#include <sys/syscall.h>#include <list>#include "Tls.h" using namespace std;  #define gettid() syscall(__NR_gettid)#define TLS_OUT_OF_INDEXES          0xffffffff typedef struct pthread_atexit{    void   (*free_fn)(void *);    void   *arg;}pthread_atexit_t; typedef std::list<pthread_atexit_t *> TlsList; pthread_key_t   Tls::_pthread_atexit_key = TLS_OUT_OF_INDEXES;pthread_once_t  Tls::_pthread_atexit_control_once = PTHREAD_ONCE_INIT; void Tls::pthread_atexit_done(void *arg){    TlsList *id_list = (TlsList*) arg;    pthread_atexit_t *id_ptr=NULL;    printf("invoke Tls::pthread_atexit_done(): tid=%ld\n",gettid());    for(TlsList::iterator iter=id_list->begin(); iter !=id_list->end(); ++iter)    {        id_ptr = *iter;        if (id_ptr == NULL)            continue;        if (id_ptr->free_fn)            id_ptr->free_fn(id_ptr->arg);        delete id_ptr;    }    delete id_list;} void Tls::pthread_atexit_init(void){    pthread_key_create(&_pthread_atexit_key, pthread_atexit_done);} int Tls::pthread_atexit_add(void *arg, void (*free_fn)(void *)){    const char *myname = "pthread_atexit_add";    pthread_atexit_t *id;    TlsList *id_list;     if (arg == NULL)    {        return 0;    }    pthread_once(&_pthread_atexit_control_once, pthread_atexit_init);    if (_pthread_atexit_key == (pthread_key_t) TLS_OUT_OF_INDEXES)    {        printf("%s(%d): _pthread_atexit_key(%d) invalid\n",                myname, __LINE__, _pthread_atexit_key);        return (-1);    }     id = new pthread_atexit_t;    if (id == NULL)    {        printf("%s(%d): new pthread_atexit_t error\n", myname, __LINE__);        return -1;    }    id->free_fn = free_fn;    id->arg = arg;     id_list = (TlsList*) pthread_getspecific(_pthread_atexit_key);    if (id_list == NULL)    {        id_list = new TlsList();        if (pthread_setspecific(_pthread_atexit_key, id_list) != 0)        {            printf("%s(%d): pthread_setspecific error, key(%d)\n",                    myname, __LINE__, _pthread_atexit_key);            return -1;        }    }    id_list->push_back(id);    return 0;} int Tls::pthread_atexit_remove(void *arg, void (*free_fn)(void*)){    const char *myname = "pthread_atexit_remove";    TlsList *id_list;     if (arg == NULL)    {        return (-1);    }    if (_pthread_atexit_key == (pthread_key_t) TLS_OUT_OF_INDEXES)    {        printf("%s(%d): _pthread_atexit_key(%d)  invalid\n",myname, __LINE__, _pthread_atexit_key);        return (-1);    }    id_list = (TlsList*) pthread_getspecific(_pthread_atexit_key);    if (id_list == NULL)    {        printf("%s(%d): _pthread_atexit_key(%d) no exist in tid(%lu)\n",            myname, __LINE__, _pthread_atexit_key,(unsigned long) pthread_self());        return (-1);    }    pthread_atexit_t *id_ptr =NULL;    TlsList::iterator iter=id_list->begin();    for(; iter !=id_list->end(); ++iter)    {        id_ptr = *iter;        if (id_ptr == NULL)            continue;        if (id_ptr->free_fn == free_fn && id_ptr->arg == arg)        {            break;        }    }    if(id_ptr != NULL)    {        id_list->erase(iter);        delete id_ptr;    }    return (0);}

使用方法:
1) #include “Tls.h”
2) 用 __thread 声明某类型的线程局部变量指针
3) 定义该线程局部变量的内存释放函数
4) 第一次使用该线程局部变量时,分配内存并调用pthread_atexit_add注册内存释放函数

更多参考:点击打开链接

0 0
原创粉丝点击