首页 > 代码库 > 线程局部存储 TLS
线程局部存储 TLS
C/C++运行库提供了TLS(线程局部存储),在多线程还未产生时,可以将数据与正在执行的线程关联。strtok()函数就是一个很好的例子。与它一起的还有strtok_s(),_tcstok_s()等等函数,其实_tcs 是 wcs 的另外一种写法,表示宽字符存储,_s 是微软定义的安全函数,通常比普通函数多一个参数。以_tcstok_s()为例,
int main(int argc, char* argv[])
{
wchar_t Source[] = L"192.168.255.255";
wchar_t doc[] = L".";
wchar_t* next_token;
wchar_t* Dest = _tcstok_s(Source, doc, &next_token); //strtok_s
int i = 1;
while (Dest != NULL)
{
printf("Dest[%d]: %S\r\n", i, Dest);
Dest = _tcstok_s(NULL, doc, &next_token);
i++;
}
return 0;
}
如果提示函数不认识,添加头文件 #include <tchar.h>
代码很简单,将源字符串以 “.”为分隔符分开,并输出。注意第二次调用_tcstok_s函数时,第一参数传NULL,这是因为第一次调用时已经将字符串保存在自己的静态变量中,后面再使用就可以引用保存的地址。
但在多线程编程下,第一个线程调用_tcstok_s,当它再次调用之前,另一个线程也可能调用它。这样就导致第一次的内容被覆盖。这就用到TLS的内容了。
1.静态TLS
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
__declspec(thread) int value = 0;
DWORD WINAPI ThreadProc(LPVOID Param);
int main(int argc, char* argv[])
{
value = http://www.mamicode.com/1;
HANDLE ThreadHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
WaitForSingleObject(ThreadHandle, INFINITE);
cout << "main " << value << endl;
return 0;
}
DWORD WINAPI ThreadProc(LPVOID Param)
{
value = http://www.mamicode.com/10;
cout << value << endl;
return 0;
}
__declspec(thread) 这个修饰符告诉编译器,将这个值放在.tls段中,如果不写,会放在.data段里。
结果:
定义了__declspec(thread) 输出 10 main 1
没定义__declspec(thread) 输出 10 main 10
2.动态TLS
#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;
int __Index[3] = { 0 };
char Name[3][20] = { {"qwe"},{"asd"},{"zxc"} };
DWORD WINAPI ThreadProc(LPVOID Param);
int main(int argc, char* argv[])
{
int i = 0;
DWORD ThreadID[3] = { 0 };
HANDLE ThreadHandle[3] = { 0 };
for (; i < 3; i++)
{
__Index[i] = TlsAlloc(); // 对位标志进行检索,找到一个FREE标志,其实就是预定了一个索引
if (__Index[i] <= TLS_MINIMUM_AVAILABLE)
{
ThreadHandle[i] = CreateThread(NULL, 0, ThreadProc, (LPVOID)(Name[i]), 0, &ThreadID[i]);
}
}
WaitForMultipleObjects(3, ThreadHandle, TRUE, INFINITE);
return 0;
}
DWORD WINAPI ThreadProc(LPVOID Param)
{
char* key = new char[20];
memcpy(key, (char*)Param, 20);
TlsSetValue(__Index[0], key); //将值与索引关联,注意,微软实现它时,牺牲了错误检查,即使错误的索引,也会分配
for (int i = 0; i < 10; i++)
{
Sleep(1);
printf("%s\r\n", (char*)TlsGetValue(__Index[0])); // 返回 索引中的值
}
free(key);
return 0;
}
一般来说,这两种TLS在创建DLL时更加有用。
线程局部存储 TLS