動態tls的使用

多線程的時候最好不要使用全局和靜態變量,因爲如果一個線程改變了全局變量的值,另一個線程在不知情的情況下有可能引用這個變量導致不可預料的錯誤
我們先舉個例子
假設兩個線程各自從0-9999計數
如果我們這樣寫
main.cpp

#include <Windows.h>
#include <stdio.h>
DWORD WINAPI WorkThread(LPVOID param);
DWORD g_dwNumber = 0;//舊版有問題
int main()
{
    g_TlsIndex = TlsAlloc();
    HANDLE hThread[2];
    for (int i = 0; i < 2; i++)
    {
        hThread[i]= CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
    }
    WaitForMultipleObjects(2, hThread, true, INFINITE);
    printf("%d", g_TlsIndex);
    system("pause");
    return 0;
}

DWORD WINAPI WorkThread(LPVOID param)
{
    for (int i = 0; i < 10000; i++)
    {
        printf("PID=%d g_dwNumber=%d\n", GetCurrentThreadId(), g_dwNumber++);
    }
    return 0;
}

運行結果
這裏寫圖片描述
最後的計數結果達到了19999,很顯然是錯誤的
這個時候就是動態tls派上用場的時候了,動態tls其實就是爲每個線程創建一個與其關聯的內存塊,這個內存塊可以當數組使用
TlsAlloc可以分配一個沒有用過的索引給你,讓你在裏面寫入東西
這裏需要注意的一點是隻要申請了一個索引,所有的線程都能使用這個索引,但是索引所在位置的內容是與線程相關的
打個比方,一個市有市長,副市長,地稅局長,國稅局長,招商局張,教育局長等等,市就相當於線程,而省相當於進程,每個市的市長和副市長都是不一樣,所以說,每個線程每個tls數組相關索引裏面的內容都是跟線程相關的
使用動態tls需要4個函數
TlsAlloc() 分配可用的tls索引
TlsFree(DWORD dwTlsIndex) 釋放索引,這樣下次可以繼續使用
TlsSetValue(DWORD dwTlsIndex,LPVOID p) 爲tls數組索引位置設置數據
TlsGetValue(DWORD dwTlsIndex) 獲取tls數組索引位置的數據
下面我們舉個例子吧

#include <Windows.h>
#include <stdio.h>
DWORD WINAPI WorkThreadNew(LPVOID param);
DWORD g_TlsIndex = 0;//tls添加
int main()
{
    g_TlsIndex = TlsAlloc();//使用之前先分配一個索引
    HANDLE hThread[2];
    for (int i = 0; i < 2; i++)
    {
        hThread[i]= CreateThread(NULL, 0, WorkThreadNew, NULL, 0, NULL);
    }
    WaitForMultipleObjects(2, hThread, true, INFINITE);
    printf("%d", g_TlsIndex);
    TlsFree(g_TlsIndex);
    system("pause");
    return 0;
}
DWORD WINAPI WorkThreadNew(LPVOID param)
{
    TlsSetValue(g_TlsIndex, 0);
    for (int i = 0; i < 10000; i++)
    {
        int n = (int)TlsGetValue(g_TlsIndex);
        Sleep(1);
        printf("PID=%d g_dwNumber=%d\n", GetCurrentThreadId(), n);
        TlsSetValue(g_TlsIndex, (LPVOID)(++n));
    }
    return 0;
}

這裏寫圖片描述
大功告成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章