2011年10月1日 星期六

Thread Local Storage

在撰寫多緒的軟體時難免會發生主、副執行緒使用同份資料的情況…
有一個修飾字可以讓一個變數安全的讓每個 Thread 都取用同樣的資料即 volatile
但我們如果想要反過來讓每個 Thread 不會影響各自的資料呢?就得用到 TLS 嘍…

MSDN 官方的文件說明在 Visual Studio 中怎麼宣告 TLS 變數:Thread Local Storage

當然要達到 TLS 的方法其實非常多…流程上可行的話…使用 mutex 是更簡單易維護的方式…
再者讓 Thread 的主體中複製一份該變數的內容也可以…但若會使用到的資料多起來會相當累人…
或者就是簡單在全域的變數宣告前面加上 __declspec(thread) 即可達到 TLS 的效果…
以下使用簡單的範例說明使用了 __declspec(thread) 的效果…


__declspec(thread) int g_nTLS = 0;

UINT SampleThread(LPVOID pParam)
{
 int *nThread = (int*)pParam;

 do
 {
  cout << "Thread Number : " << *nThread << " : " << g_nTLS++;
 } while (g_nTLS < 1000000);

 return TRUE;
}

void StartTwoThread()
{
 int x = 1, y = 2;
 AfxBeginThread(SampleThread, (LPVOID)&x, THREAD_PRIORITY_NORMAL);
 AfxBeginThread(SampleThread, (LPVOID)&y, THREAD_PRIORITY_NORMAL);
}


若全域變數 g_nTLS 沒有宣告為 TLS 變數…
輸出的結果應該會看到不規則的有時 g_nTLS 被第 1 個啟動的 Thread 加了有時被第 2 個…
加了 __declspec(thread) 後…雖然印出來的順序不一定整齊…
但至少 Thread 1、2 都會乖乖的印出自己的 0-999999

如果覺得 __ 開頭的這種修飾字很難看…也可以像 MSDN 文件裡一樣


#define Thread __declspec( thread )


再改用 Thread int tls_i; 宣告也行…
此外宣告 TLS 變數的對像也有些限制,MSDN 中都有範例…

沒有留言:

張貼留言