VC++中线程局部存储(TLS)的使用
VC++中线程局部存储(TLS)的使用
线程的局部存储(Thread Local Storage,TLS)是一种线程私有的数据存储方式,每个线程都有自己的局部存储空间,可以在其中存储线程私有的数据。线程的局部存储原理是通过操作系统提供的API实现的,不同的操作系统提供的API可能有所不同,下面以 Windows操作系统为例进行说明。
在Windows操作系统中,线程的局部存储是通过TLS函数实现的。TLS函数包括以下几个步骤:
- 调用TlsAlloc函数分配一个TLS索引,该索引用于访问线程的局部存储空间。
- 调用TlsSetValue函数将数据存储到线程的局部存储空间中,可以使用任何类型的数据作为线程的局部存储数据。
- 调用TlsGetValue函数从线程的局部存储空间中获取数据。
- 调用TlsFree函数释放线程的局部存储空间。
在使用TLS函数时,需要注意以下几点:
- 每个线程都有自己的局部存储空间,线程之间的数据不会相互干扰。
- 线程的局部存储空间是在线程创建时分配的,线程退出时释放。
- 线程的局部存储空间大小是固定的,通常为4KB。
- 线程的局部存储空间可以存储任何类型的数据,包括指针、整数、结构体等。
总之,线程的局部存储是一种线程私有的数据存储方式,可以在其中存储线程私有的数据。线程的局部存储原理是通过操作系统提供的API实现的,不同的操作系统提供的API可能有所不同。在使用TLS函数时,需要注意线程之间的数据不会相互干扰,线程的局部存储空间大小是固定的,可以存储任何类型的数据。
下面是一个使用线程局部存储(TLS)编写的Windows C++多线程程序示例:
#include <iostream>
#include <Windows.h>
#include <string>
#include <sstream>
// 全局变量,用于记录线程 ID
DWORD g_threadId = 0;
// 定义线程局部存储 TLS_KEY
DWORD tlsKey = TlsAlloc();
/**
* 线程入口函数
* 输出 10 次线程 ID 和 TLS 存储的数值
*/
DWORD WINAPI ThreadProc(LPVOID lpParameter) {
int num = 0;
// 设置 TLS 存储的数值
TlsSetValue(tlsKey, new int(1));
for (int i = 0; i < 10; i++) {
// 输出线程 ID 和 TLS 存储的数值
std::stringstream ss;
ss << "Thread ID " << g_threadId << ", TLS value " << num << std::endl;
std::string output = ss.str();
std::cout << output;
// 每次循环将 TLS 存储的数值加 1
num++;
int* numPtr = static_cast<int*>(TlsGetValue(tlsKey));
(*numPtr)++;
}
// 释放 TLS 存储的内存
int* numPtr = static_cast<int*>(TlsGetValue(tlsKey));
delete numPtr;
TlsFree(tlsKey);
return 0;
}
int main()
{
const int THREAD_COUNT = 3;
HANDLE threads[THREAD_COUNT];
// 创建多个线程
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
// 记录线程 ID
g_threadId = GetThreadId(threads[i]);
}
// 等待所有线程结束
WaitForMultipleObjects(THREAD_COUNT, threads, TRUE, INFINITE);
return 0;
}
在上述代码中,TlsAlloc() 用于分配一个新的 TLS 键,TlsSetValue() 用于为指定的线程设置给定的 TLS 数据指针,TlsGetValue() 用于获取指定线程的 TLS 数据指针,TlsFree() 用于释放一个指定的 TLS 键。
在 ThreadProc() 函数中,我们先使用 TlsSetValue() 将存储的数值初始化为 1,然后循环输出线程 ID 和 TLS 存储的数值,每次循环将 TLS 存储的数值加 1。再在线程结束时,使用 TlsGetValue() 获取 TLS 存储的数值指针,释放内存并释放 TLS 键。
在 main() 函数中,我们创建多个线程,并且记录每个线程的 ID。最后,我们使用 WaitForMultipleObjects() 等待所有线程结束。
该文章会更新,欢迎大家批评指正。
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:
服务器课程:C++服务器