c/c++ 线程私有数据

       我们知道,不管是在单线程还是在多线程中,全局变量都可以在各线程中共享数据。但当我们需要在各线程中保存各自线程的数据时,该如何处理呢?是在各线程中各自定义数据呢,还是有其他办法呢?pthread 线程库就有这样一种数据结构,  相同的数据名称在不同的线程中各自维护着各自的数据,称为线程私有数据(Thread Specific Data TSD)或称为 线程本地存储 TSS(Thread-Specific Storage), TLS(Thread Local Storage)。而 pthread 线程库一共提供了 4 个接口用来创建、删除、设置、获取 这个线程私有数据,分别为:

 #include <pthread.h> 

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)); //第 2 个参数是一个函数指针,用来在线程退出时将key值作为参数进行调用。(这个参数暂时没用过)

 int pthread_key_delete(pthread_key_t key);

 int pthread_setspecific(pthread_key_t key, const void *value);

 void *pthread_getspecific(pthread_key_t key);

类型 pthread_key_t 实际定义为:

/* Keys for thread-specific data */

typedef unsigned int pthread_key_t;

我们可以用一个类进行封装,如下:

/************************************
*
* filename: ThreadSpecific.h
*
************************************/

#ifndef __THREAD_SPECIFIC_H__
#define __THREAD_SPECIFIC_H__

#include <pthread.h>

class CThreadSpecific
{
public:
    CThreadSpecific();
    ~CThreadSpecific();

    // 设置私有数据
    bool setValue(void const *value);

    // 获取私有数据
    bool getValue(void **value);

private:
    bool            mValid; //数据是否可用,即调用 pthread_key_create 过了
    pthread_key_t   mKey;

};


#endif
/************************************
*
* filename: ThreadSpecific.cpp
*
************************************/

#include "ThreadSpecific.h"

CThreadSpecific::CThreadSpecific(): mValid(false), mKey(0)
{
    mValid = (0 == pthread_key_create(&mKey, NULL));
}

CThreadSpecific::~CThreadSpecific()
{
    if(mValid)
    {
        pthread_key_delete(mKey);
    }
}

bool CThreadSpecific::setValue(void const *value)
{
    if(mValid)
    {
        return 0 == pthread_setspecific(mKey, value);
    }

    return false;
}

bool CThreadSpecific::getValue(void **value)
{
    if(mValid)
    {
        *value = pthread_getspecific(mKey);
        return true;
    }

    return false;
}

        那线程私有数据有什么用呢?毫无疑问是用在多线程情况下,比如场景:一台嵌入式设备可以通过局域网进行登录,登录后可以进行配置操作或其他操作,而同时它是允许多个用户操作的,这时多个用户操作其实就是多个线程在操作,那么各个用户(线程)获取到的返回码肯定是要不一样的。假如用一个全局变量会发生什么样的情况呢?可能是:前一个用户操作错误时,紧接着一个用户操作没有错误,而取到是前一个用户操作的错误码,这样是不是混乱了呢?所以这种情况下,各个线程操作的结果应该是各个线程进行私有设置,这样各个线程获取到的错误码才是正确的。

        那实际使用时可以再添加一个管理错误码的类,实现为一个单例,然后提供设置和获取错误码的接口,类似如下:

/****************************
 * filename: ErrorManager.h
 ***************************/
#ifndef __ERROR_MANAGER_H__
#define __ERROR_MANAGER_H__

#include "ThreadSpecific.h"

class CErrorManager
{
private:
    CErrorManager()
    {}
    ~CErrorManager()
    {}

    CErrorManager(const CErrorManager&) = delete;
    CErrorManager& operator=(const CErrorManager&) = delete;

public:
    static CErrorManager *instance();

    bool setLastError(int errno);

    int getLastError();
};

#endif
/*******************************
 * filename: ErrorManager.cpp
 ******************************/

#include <stdint.h>
#include "ErrorManager.h"

static CThreadSpecific sTSSLastError;

CErrorManager *CErrorManager::instance()
{
    static CErrorManager sInstance;
    return &sInstance;
}

bool CErrorManager::setLastError(int errno)
{
    return sTSSLastError.setValue(reinterpret_cast<void const*>(errno));
}

int CErrorManager::getLastError()
{
    void *value = NULL;
    sTSSLastError.getValue(&value);

    return ((int)reinterpret_cast<intptr_t>(value));
}

main 函数如下,创建两个线程,用简单的 sleep() 方式先后启动线程函数,同时交叉地设置了各自的线程私有数据,然后再获取。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>
#include "ErrorManager.h"

void *threadProc(void *arg)
{
    int errNo = *(int *)arg;
    printf("tid[%ld] setLastError %d to threadspecific!\n", syscall(SYS_gettid), errNo);
    CErrorManager::instance()->setLastError(errNo);
    sleep(3);

    int value = CErrorManager::instance()->getLastError();
    printf("tid[%ld] getLastError %d from threadspecific!\n", syscall(SYS_gettid), value);

    return nullptr;
}


int main()
{
    pthread_t tid1, tid2;
    int value = 200;
    pthread_create(&tid1, nullptr, threadProc, (void *)&value);
    sleep(1);

    value = 500;
    pthread_create(&tid2, nullptr, threadProc, (void *)&value);

    pthread_join(tid1, nullptr);
    pthread_join(tid2, nullptr);

    return 0;
}

其结果为:

各个线程获取的都是各自设置的数据。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值