C C++中ThreadLocal的实现方式

C C++中ThreadLocal的实现方式

我们之前讲了Windows的线程创建方式,在创建线程时应该使用_beginthreadex函数,而不是CreateThread函数,结束线程应该用_endthreadex,当然最好是不要主动去结束,而是应该用return来结束线程。

C是不支持多线程的,因为在C开发出来的时候,多任务操作系统还没有开发出来,我们现在的处理器都是多线程的,所以现在的程序都要支持多线程,多线程程序中有一个概念是很重要的,那就是threadlocal,我们都知道在C中有一个errno全局变量,可以让我们通过GetLastError()方法来获取错误代码,但是如果是多线程的程序的话,很多线程都同时在改这一个变量,很可能我们获取到的就是其他线程设置的errno了,threadlocal就是要解决这种问题的,有了threadlocal每个线程中的errno都是他自己的,其他线程无法更改你的errno。

ThreadLocal实现原理

上面我们了解了ThreadLocal的作用,就是要保存每个线程自己的变量副本,每个线程都有一个自己的线程运行栈(是用户空间还是内核空间呢?待考察–),堆空间是所有线程共有的进程的用户空间。

如果我们创建线程时用_beginthreadex函数的话,这个函数内部会为我们创建一个 _tiddata结构,如果是我们可以将需要作为线程独立的变量放在这个区域,这就可以使用TlsGetValue来获取threadlocal变量。


我们来看看_beginthreadex的伪代码,其实这个函数的源码是可以看到的,在VC的crt/src/Threadex.c中,这里的伪代码更加的结构更加清晰

uintptr_r __cdecl _beginthreadex
(
void *psa,
unsigned cbStackSize;
unsigned (__stdcall * pfnStartAddr)(void*),
void *pvParam,
unsigned dwCreateFlags,
unsigned *pwdThreadID
)
{
    _ptiddata ptd;  // pointer to thread's data block
    uintptr_r thdl; //Thread's HANDLE

    //Allocate data block for new thread
    //为新线程分配数据区域
    if((ptd=(_ptiddata)_calloc_crt(1,sizeof(struct _tiddata))) == NULL) goto error_return;

    // Initilize the data block
    initptd(ptd);

    //Save the desired thread function and the parameter we want to get in the data block
    //将线程的函数和参数放入这块数据区域
    ptd->_initaddr = (void *)pfnStartAddr;
    ptd->_initarg = pvParam;
    ptd->_thandle = (uintptr_t)(-1);

    //Create the thread
    thdl = (uintptr_t)CreateThread((LPSECURITY_ATTRIBUTES)pas,cbStackSize,
            _threadstartex,(PVOID)ptd,dwCreateFlags,pwdThreadID);
    if(thdl == 0){
        // thread can not be created 
        
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++,并没有直接提供类似JavaThreadLocal类。但是,我们可以通过使用线程局部存储(Thread Local Storage,TLS)来实现类似的功能。 TLS是一种机制,允许在多线程环境为每个线程分配独立的存储空间。每个线程可以访问自己的存储空间,而不会与其他线程的存储空间发生冲突。 在C++,我们可以使用操作系统提供的API来实现TLS。下面是一个使用Windows API的示例: ```cpp #include <windows.h> // 定义一个全局的TLS索引 DWORD tlsIndex; // 线程入口函数 DWORD WINAPI ThreadFunc(LPVOID lpParam) { // 获取当前线程的TLS变量 int* threadData = static_cast<int*>(TlsGetValue(tlsIndex)); if (threadData == nullptr) { // 如果TLS变量为空,说明还未分配,进行初始化 threadData = new int(0); TlsSetValue(tlsIndex, threadData); } // 使用TLS变量 (*threadData)++; // 输出TLS变量的值 printf("Thread %u: TLS value = %d\n", GetCurrentThreadId(), *threadData); return 0; } int main() { // 创建一个TLS索引 tlsIndex = TlsAlloc(); // 创建多个线程 HANDLE threads[5]; for (int i = 0; i < 5; ++i) { threads[i] = CreateThread(nullptr, 0, ThreadFunc, nullptr, 0, nullptr); } // 等待线程结束 WaitForMultipleObjects(5, threads, TRUE, INFINITE); // 释放TLS索引 TlsFree(tlsIndex); return 0; } ``` 上面的示例演示了如何使用Windows API来实现线程局部存储。在每个线程,我们通过调用TlsGetValue函数来获取当前线程的TLS变量,如果变量为空,则进行初始化并使用TlsSetValue函数设置变量的值。在主线程,我们创建了多个线程,并等待它们结束。最后,我们释放了TLS索引。 需要注意的是,不同的操作系统可能提供不同的TLS实现方式。在Linux,可以使用pthread库提供的函数来实现TLS。具体实现方式可能会有所不同,可以根据具体情况进行调整。 希望这个例子能帮助你理解C++的线程局部存储。如果还有其他问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值