青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++ Programmer's Cookbook

{C++ 基礎(chǔ)} {C++ 高級} {C#界面,C++核心算法} {設(shè)計模式} {C#基礎(chǔ)}

C++多線程(九)

多線程之線程局部存儲

一 線程局部存儲 (TLS)
      來自:http://msdn2.microsoft.com/en-us/library/ms686749.aspx
      
      同一進程中的所有線程共享相同的虛擬地址空間。不同的線程中的局部變量有不同的副本,但是static和globl變量是同一進程中的所有線程共享的。使用TLS技術(shù)可以為static和globl的變量,根據(jù)當前進程的線程數(shù)量創(chuàng)建一個array,每個線程可以通過array的index來訪問對應(yīng)的變量,這樣也就保證了static和global的變量為每一個線程都創(chuàng)建不同的副本。

二 線程局部存儲(TLS)實現(xiàn)使用

1)TLS 的 API 實現(xiàn)
通過 Win32 API 層和編譯器實現(xiàn)“線程本地存儲”。有關(guān)詳細信息,請參見 Win32 API 文檔中的 TlsAlloc、TlsGetValue、TlsSetValue 和 TlsFree。 (下面的代碼對msdn的稍加修改)

#include <windows.h> 
#include 
<stdio.h> 

#define THREADCOUNT 10
DWORD dwTlsIndex;  

static int g_x = 100;  // test static var for multiple threading

VOID ErrorExit(LPSTR); 

VOID CommonFunc(VOID) 

    LPVOID lpvData; 

    
// Retrieve a data pointer for the current thread. 
    lpvData = TlsGetValue(dwTlsIndex); 
    
if ((lpvData == 0&& (GetLastError() != ERROR_SUCCESS)) 
        ErrorExit(
"TlsGetValue error"); 
    
int *pg_x = (int*)lpvData;

    
// Use the data stored for the current thread. 
    printf("thread %d: g_x adress=%lx,g_x copy ++ = %d\n", GetCurrentThreadId(), pg_x, *pg_x);
    Sleep(
1000); 
}
 

DWORD WINAPI ThreadFunc(VOID) 

    LPVOID lpvData; 

    
// Initialize the TLS index for this thread. 
    lpvData = (LPVOID) LocalAlloc(LPTR, 256); 
    
//*(int*)lpvData = g_x;
    int *pg_x = (int*)lpvData;
    
*pg_x = g_x;
    
if (! TlsSetValue(dwTlsIndex, lpvData)) 
        ErrorExit(
"TlsSetValue error");     

    printf(
"thread %d: g_x adress=%lx,g_x copy = %d\n", GetCurrentThreadId(), pg_x, *pg_x);

    InterlockedExchangeAdd(reinterpret_cast
<long*>(pg_x),1);
    CommonFunc(); 

    
// Release the dynamic memory before the thread returns.
    lpvData = TlsGetValue(dwTlsIndex); 
    
if (lpvData != 0
        LocalFree((HLOCAL) lpvData); 

    
return 0
}
 

int main(VOID) 

    DWORD IDThread; 
    HANDLE hThread[THREADCOUNT]; 
    
int i; 

    printf(
"main thread: g_x is :%d\n",g_x);

    
// Allocate a TLS index.  
    if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
        ErrorExit(
"TlsAlloc failed"); 

    
//test for multiple static or global var
    int dwTlsIndex2 = TlsAlloc();

    
// Create multiple threads. 
    for (i = 0; i < THREADCOUNT; i++
    

        hThread[i] 
= CreateThread(NULL, // default security attributes 
            0,                           // use default stack size 
            (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function 
            NULL,                    // no thread function argument 
            0,                       // use default creation flags 
            &IDThread);              // returns thread identifier 

        
// Check the return value for success. 
        if (hThread[i] == NULL) 
            ErrorExit(
"CreateThread error\n"); 
    }
 

    
for (i = 0; i < THREADCOUNT; i++
        WaitForSingleObject(hThread[i], INFINITE); 

    TlsFree(dwTlsIndex);

    printf(
"main thread: g_x is :%d\n",g_x);
    
return 0
}
 

VOID ErrorExit (LPSTR lpszMessage) 

    fprintf(stderr, 
"%s\n", lpszMessage); 
    ExitProcess(
0); 
}

運行結(jié)果:(可以看出不同的線程中的g_x變量有不同的地址,即有不同的拷貝,主線程變量在開始和最后都不被改變。)

PS: (TLS的實現(xiàn)原理與API解釋)
1:在多線程的進程中,為每一個static或是global變量創(chuàng)建一個void*的數(shù)組,使變量不同線程都有一個拷貝,然后拷貝的指針放入Void*的數(shù)組中。
2:TlsAlloc() 得到對應(yīng)于一個static或global變量所對應(yīng)的void*的數(shù)組的索引,這個用來標示不同static或global變量所對應(yīng)的void*的數(shù)組。
3:LocalAlloc()用來分配變量在此線程的拷貝的指針。
4:TlsSetValue()用來把剛分配的指針加到所對應(yīng)的void*的數(shù)組中,加入后一般對會對此指針賦值供此線程使用。
5:TlsGetValue()用來從對應(yīng)的void*的數(shù)組中找到此線程所對應(yīng)的拷貝的指針。
6:   TlsFree() 釋放整個void*的指針數(shù)組。



2)TLS 的編譯器實現(xiàn)

為了支持 TLS,已將新屬性 thread 添加到了 C 和 C++ 語言,并由 Visual C++ 編譯器支持。使用 __declspec 關(guān)鍵字聲明 thread 變量。例如,以下代碼聲明了一個整數(shù)線程局部變量,并用一個值對其進行初始化:

__declspec( thread ) int tls_i = 1;

下面的代碼使用了VC提供的__declspec關(guān)鍵字來實現(xiàn)TLS,如果不使用TLS,全局變量g_x則在線程中輸出的結(jié)果都是1,2,3,4.。。。但是如果使用TLS則在線程中輸出的結(jié)果都是1,編譯器幫我們保證了每個線程都有一個副本。 我們還可以看到主線程在開始和最后輸出的g_x都是0,這也更說明了在線程有不同的副本。

#include <windows.h> 
#include 
<stdio.h> 
 
#define THREADCOUNT 10

DWORD dwTlsIndex; 

//static int g_x = 0;

#define Thread  __declspec(thread)
Thread 
static int g_x = 0;

VOID ErrorExit(LPSTR); 
 
DWORD WINAPI ThreadFunc(VOID) 

  InterlockedExchangeAdd(reinterpret_cast
<long*>(&g_x),1); //g_x+=1;   
  printf("thread id: %d, g_x++ = %d, g_x adress = %d\n",GetCurrentThreadId(),g_x,&g_x);
  
return 1
}
 
 
int main(VOID) 

   DWORD IDThread; 
   HANDLE hThread[THREADCOUNT]; 
   
int i; 

    printf(
"main thread: g_x = %d, g_x adress = %d\n",g_x,&g_x);
  
// Create multiple threads.  
   for (i = 0; i < THREADCOUNT; i++
   

      hThread[i] 
= CreateThread(NULL, // default security attributes 
         0,                           // use default stack size 
         (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function 
         NULL,                    // no thread function argument 
         0,                       // use default creation flags 
         &IDThread);              // returns thread identifier 
 
   
// Check the return value for success. 
      if (hThread[i] == NULL) 
         ErrorExit(
"CreateThread error\n"); 
   }
 
 
   
for (i = 0; i < THREADCOUNT; i++
      WaitForSingleObject(hThread[i], INFINITE); 
  

   printf(
"main thread: g_x = %d, g_x adress = %d\n",g_x,&g_x);
   
return 0
}
 
 
VOID ErrorExit (LPSTR lpszMessage) 

   fprintf(stderr, 
"%s\n", lpszMessage); 
   ExitProcess(
0); 

運行結(jié)果:

三 使用VC關(guān)鍵字實現(xiàn)TLS需要注意:

聲明靜態(tài)綁定線程的本地對象和變量時必須遵守下列原則:

  • thread 屬性只能應(yīng)用于數(shù)據(jù)聲明和定義。它不能用于函數(shù)聲明或定義。例如,以下代碼將生成一個編譯器錯誤:
    #define Thread  __declspec( thread )
        Thread void func();     // This will generate an error.
  • 只能在具有 static 作用域的數(shù)據(jù)項上指定 thread 修飾符。包括全局數(shù)據(jù)對象(包括 staticextern)、本地靜態(tài)對象和 C++ 類的靜態(tài)數(shù)據(jù)成員。不可以用 thread 屬性聲明自動數(shù)據(jù)對象。以下代碼將生成編譯器錯誤:
    #define Thread  __declspec( thread )
        void func1()
        {
        Thread int tls_i;            // This will generate an error.
        }
        int func2( Thread int tls_i )    // This will generate an error.
        {
        return tls_i;
        }
  • 線程本地對象的聲明和定義必須全都指定 thread 屬性。例如,以下代碼將生成錯誤:
    #define Thread  __declspec( thread )
        extern int tls_i;        // This will generate an error, since the
        int Thread tls_i;        // declaration and definition differ.
  • thread 屬性不能用作類型修飾符。例如,以下代碼將生成一個編譯器錯誤:
    char __declspec( thread ) *ch;        // Error
  • C++ 類不能使用 thread 屬性。但是,可以使用 thread 屬性將 C++ 類對象實例化。例如,以下代碼將生成一個編譯器錯誤:
    #define Thread  __declspec( thread )
        class Thread C       // Error: classes cannot be declared Thread.
        {
        // Code
        };
        C CObject;

    因為允許使用 thread 屬性的 C++ 對象的聲明,因此下面兩個示例在語義上是等效的:

    #define Thread  __declspec( thread )
        Thread class B
        {
        // Code
        } BObject;               // OK--BObject is declared thread local.
        class B
        {
        // Code
        };
        Thread B BObject;        // OK--BObject is declared thread local.
  • 不將線程本地對象的地址視為常數(shù),并且涉及此類地址的任何表達式都不視為常數(shù)。在標準 C 中,這種作法的效果是禁止將線程本地變量的地址用作對象或指針的初始值設(shè)定項。例如,C 編譯器將以下代碼標記為錯誤:
    #define Thread  __declspec( thread )
        Thread int tls_i;
        int *p = &tls_i;       //This will generate an error in C.

    但是,此限制不適用于 C++。因為 C++ 允許動態(tài)初始化所有對象,因此可以用使用線程本地變量地址的表達式初始化對象。實現(xiàn)此操作的方式與實現(xiàn)線程本地對象結(jié)構(gòu)的方式相同。例如,以上顯示的代碼在作為 C++ 源文件編譯時不會生成錯誤。請注意:只有在其中獲取地址的線程仍然存在的情況下,線程本地變量的地址才有效。

  • 標準 C 允許使用涉及引用自身的表達式初始化對象或變量,但只適用于非靜態(tài)作用域的對象。雖然 C++ 通常允許使用涉及引用自身的表達式動態(tài)初始化對象,但是這種類型的初始化不允許用于線程本地對象。例如:
    #define Thread  __declspec( thread )
        Thread int tls_i = tls_i;                // Error in C and C++
        int j = j;                               // OK in C++, error in C
        Thread int tls_i = sizeof( tls_i )       // Legal in C and C++

    請注意:包含正在初始化的對象的 sizeof 表達式不建立對自身的引用且在 C 和 C++ 中都是合法的。

    C++ 不允許此類對線程數(shù)據(jù)的動態(tài)初始化,因為將來可能要對線程本地存儲功能進行增強。

  • 如果 DLL 將任何非本地數(shù)據(jù)或?qū)ο舐暶鳛?__declspec(線程),動態(tài)加載該 DLL 時會導(dǎo)致保護錯誤。使用 LoadLibrary 加載所有 DLL 后,每當代碼引用非本地 __declspec(線程)數(shù)據(jù)時,將導(dǎo)致系統(tǒng)故障。由于線程的全局變量空間是在運行時分配的,因此此空間的大小是以應(yīng)用程序的需求和所有靜態(tài)鏈接的 DLL 的需求相加為基礎(chǔ)計算出來的。使用 LoadLibrary 時,無法擴展此空間以允許放置用 __declspec(線程)聲明的線程本地變量。如果 DLL 可能是用 LoadLibrary 加載的,請在 DLL 中使用 TLS API(如 TlsAlloc)來分配 TLS。

四  DLL使用TLS :http://msdn2.microsoft.com/en-us/library/ms686997.aspx
    

posted on 2007-08-01 15:38 夢在天涯 閱讀(5974) 評論(0)  編輯 收藏 引用 所屬分類: CPlusPlus

公告

EMail:itech001#126.com

導(dǎo)航

統(tǒng)計

  • 隨筆 - 461
  • 文章 - 4
  • 評論 - 746
  • 引用 - 0

常用鏈接

隨筆分類

隨筆檔案

收藏夾

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

積分與排名

  • 積分 - 1812203
  • 排名 - 5

最新評論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
      <noscript id="pjuwb"></noscript>
            <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
              <dd id="pjuwb"></dd>
              <abbr id="pjuwb"></abbr>
              一区二区免费在线观看| 亚洲精品在线三区| 久久精品卡一| 欧美主播一区二区三区| 激情成人av| 欧美黄色影院| 国产精品porn| 久久精品国产99| 美女免费视频一区| 一区二区久久久久| 午夜欧美不卡精品aaaaa| 黄色精品一区| 亚洲美女一区| 国产一区香蕉久久| 亚洲国产另类 国产精品国产免费| 欧美一区亚洲一区| 亚洲欧洲日产国产网站| 日韩一级大片| 久热国产精品视频| 国产精品区一区二区三区| 亚洲国产天堂久久综合网| 亚洲人成人一区二区三区| 国产精品视频一二三| 巨乳诱惑日韩免费av| 欧美三级乱人伦电影| 久久久精品tv| 欧美三级特黄| 免费看精品久久片| 国产精品久久久久久一区二区三区| 久久人人爽人人爽| 欧美日韩综合不卡| 欧美插天视频在线播放| 国产精品一区免费视频| 欧美福利视频在线观看| 国产女人aaa级久久久级| 亚洲国产一区二区精品专区| 国产农村妇女毛片精品久久莱园子| 欧美高清不卡| 狠狠色丁香久久婷婷综合丁香| 亚洲美女中出| 亚洲精品视频在线看| 欧美综合国产精品久久丁香| 亚洲永久在线| 欧美高清成人| 免费欧美网站| 国产综合色在线| 亚洲伊人一本大道中文字幕| 99亚洲一区二区| 久久久亚洲人| 久久久999精品视频| 国产精品人人做人人爽| 亚洲美女一区| 日韩一级在线观看| 欧美成人午夜剧场免费观看| 美女日韩在线中文字幕| 国产主播一区二区| 性欧美video另类hd性玩具| 亚洲无玛一区| 欧美激情在线观看| 亚洲国内精品在线| 日韩手机在线导航| 欧美日韩成人激情| 亚洲韩国精品一区| 亚洲理论在线观看| 欧美精品色网| 99在线精品观看| 亚洲一区二区在线观看视频| 欧美精品日韩| 亚洲人成网在线播放| 一本色道久久综合| 国产精品地址| 一区二区日韩欧美| 亚洲欧美国产三级| 国产精品国产一区二区 | 国产精品高潮呻吟久久| 亚洲三级色网| aa国产精品| 欧美日韩1区2区3区| 亚洲精品国产视频| 亚洲永久免费精品| 国产麻豆91精品| 欧美一区二区网站| 美女网站久久| 亚洲国产精品t66y| 怡红院精品视频| 午夜国产精品视频免费体验区| 一本色道久久综合亚洲精品高清 | 9i看片成人免费高清| 亚洲一卡二卡三卡四卡五卡| 国产欧美在线观看一区| 久久成人免费| 亚洲欧洲精品一区二区三区不卡 | 欧美一乱一性一交一视频| 国产亚洲成精品久久| 久久亚洲国产精品一区二区 | 亚洲欧美精品suv| 国内精品一区二区三区| 亚欧美中日韩视频| 亚洲国产导航| 性久久久久久久| 影音先锋日韩有码| 欧美日韩第一区| 欧美专区第一页| 亚洲精品激情| 久久香蕉国产线看观看av| 日韩视频在线一区二区| 国产精品网曝门| 嫩草影视亚洲| 午夜激情久久久| 亚洲第一精品福利| 欧美在线你懂的| 亚洲精品乱码久久久久久日本蜜臀 | 亚洲美女黄色片| 麻豆精品视频在线观看| 国产精品99久久久久久白浆小说 | 国产性色一区二区| 国产精品大片| 欧美国产日韩xxxxx| 久久国产一区| 在线亚洲欧美视频| 亚洲精品乱码久久久久久黑人| 久久婷婷国产麻豆91天堂| 这里是久久伊人| 亚洲看片免费| 91久久精品美女| 一区二区视频免费在线观看| 国产精品一区二区在线观看网站| 欧美高清在线| 欧美成人免费全部| 久久中文字幕一区二区三区| 欧美一区激情视频在线观看| 亚洲系列中文字幕| 亚洲乱码精品一二三四区日韩在线 | 国产三区精品| 国产精品久久久久一区二区| 欧美精品久久天天躁| 欧美电影在线观看| 欧美成人第一页| 欧美不卡在线视频| 欧美极品一区| 欧美激情综合色| 欧美激情视频免费观看| 欧美黄免费看| 欧美日本国产| 欧美三级中文字幕在线观看| 久久精品国产精品| 亚洲天堂av综合网| 久久亚洲综合网| 国产精品一区二区a| 免费在线日韩av| 久久久久久久久久看片| 亚洲在线中文字幕| 亚洲欧美日本在线| 亚洲午夜免费视频| 亚洲精品一品区二品区三品区| 伊人成人在线视频| 亚洲国产经典视频| 日韩系列在线| 在线视频一区二区| 亚洲性线免费观看视频成熟| 99亚洲一区二区| 这里只有精品视频| 亚洲在线观看视频| 欧美专区在线| 久久伊人亚洲| 亚洲精品一区在线| 一区二区三区色| 欧美亚洲日本一区| 久久久国产精品亚洲一区| 蜜臀av性久久久久蜜臀aⅴ四虎| 欧美国产三级| 国产精品www| 一区二区亚洲欧洲国产日韩| 亚洲国产精品精华液网站| 宅男66日本亚洲欧美视频| 久久国产精品久久久| 久久综合伊人| 一区二区三欧美| 久久久久综合网| 欧美三级网页| 一区视频在线看| 亚洲一级电影| 欧美国产日韩a欧美在线观看| 一本色道久久精品| 麻豆av一区二区三区| 国产精品嫩草影院一区二区| 亚洲国产黄色| 久久精品一区二区| 亚洲国产精品日韩| 亚洲卡通欧美制服中文| 新67194成人永久网站| 欧美国产日韩一区二区三区| 国内精品免费在线观看| 亚洲图片欧洲图片av| 男人的天堂亚洲| 亚洲在线网站| 欧美日韩福利视频| 亚洲人成77777在线观看网| 久久久久一区二区三区| 亚洲天堂网在线观看|