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

基本类型(如(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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值