線程局部存儲 TLS

C/C++運行庫提供了TLS(線程局部存儲),在多線程還未產生時,能夠將數據與正在執行的線程關聯。strtok()函數就是一個很好的例子。與它一塊兒的還有strtok_s(),_tcstok_s()等等函數,其實_tcs 是 wcs 的另一種寫法,表示寬字符存儲,_s 是微軟定義的安全函數,一般比普通函數多一個參數。以_tcstok_s()爲例,ios

 

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>windows

代碼很簡單,將源字符串以 「.」爲分隔符分開,並輸出。注意第二次調用_tcstok_s函數時,第一參數傳NULL,這是由於第一次調用時已經將字符串保存在本身的靜態變量中,後面再使用就能夠引用保存的地址。安全

但在多線程編程下,第一個線程調用_tcstok_s,當它再次調用以前,另外一個線程也可能調用它。這樣就致使第一次的內容被覆蓋。這就用到TLS的內容了。多線程

 

1.靜態TLS函數

#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;spa

__declspec(thread)  int value  = 0;線程

DWORD WINAPI ThreadProc(LPVOID Param);索引

int main(int argc, char* argv[])
{
value = 1;
HANDLE ThreadHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);token

WaitForSingleObject(ThreadHandle, INFINITE);

cout << "main " << value << endl;
return 0;
}

DWORD WINAPI ThreadProc(LPVOID Param)
{
value = 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時更加有用。

相關文章
相關標籤/搜索