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

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>
              亚洲精选一区二区| 亚洲精品乱码久久久久久| 香蕉国产精品偷在线观看不卡| 久久一二三四| 欧美chengren| 中日韩男男gay无套| 欧美视频日韩| 欧美在线观看视频| 欧美国产国产综合| 亚洲欧美日韩精品久久久| 国产午夜亚洲精品不卡| 免费观看成人| 欧美一区二区| av不卡在线观看| 免费日韩av电影| 午夜精品电影| 亚洲午夜激情网站| 亚洲精品一区二区三| 国产日韩欧美日韩大片| 一区二区三区我不卡| 欧美日韩亚洲一区二区三区在线观看 | 精品盗摄一区二区三区| 91久久精品日日躁夜夜躁国产| 欧美视频在线视频| 国产日本欧美在线观看| 欧美午夜精彩| 欧美日韩国产123区| 免费精品99久久国产综合精品| 欧美福利视频| 狼狼综合久久久久综合网| 久久成人久久爱| 亚洲午夜久久久| 日韩性生活视频| 亚洲第一狼人社区| 久久亚洲综合色一区二区三区| 中国av一区| 免费的成人av| 性欧美xxxx视频在线观看| 亚洲午夜羞羞片| 久久综合九色综合欧美就去吻| 国产精品欧美一区二区三区奶水| 欧美日韩国产欧| 在线激情影院一区| 在线免费精品视频| 先锋影音国产一区| 夜夜嗨av一区二区三区四季av| 久久免费一区| 精品96久久久久久中文字幕无| 午夜精品一区二区三区四区 | 性欧美精品高清| 99精品国产在热久久婷婷| 免费黄网站欧美| 在线欧美小视频| 免费在线播放第一区高清av| 欧美中文字幕| 韩日欧美一区二区三区| 在线欧美日韩国产| 久久亚洲私人国产精品va媚药| 午夜亚洲福利| 国内精品亚洲| 99re热精品| 99国产精品久久久久久久久久| 免费成人高清视频| 蜜桃av一区二区在线观看| 欧美区一区二区三区| 欧美午夜大胆人体| 亚洲一区在线免费| 欧美超级免费视 在线| 久久综合图片| 亚洲精品国产无天堂网2021| 欧美激情va永久在线播放| 在线视频精品| 久久米奇亚洲| 亚洲国产三级在线| 亚洲日本va在线观看| 伊人精品视频| 久久久999国产| 久久久99精品免费观看不卡| 午夜精品在线观看| 国产欧美日韩在线视频| 久久久精品久久久久| 欧美在线不卡| 亚洲精品偷拍| 亚洲一区精彩视频| 免费在线国产精品| 99国产精品国产精品毛片| 亚洲视频在线观看一区| 国产女人精品视频| 开心色5月久久精品| 亚洲天堂av在线免费| 国产日韩欧美中文| 欧美刺激性大交免费视频| 欧美日韩精品一区| 久久综合精品国产一区二区三区| 欧美成人情趣视频| 亚洲激情女人| 一二美女精品欧洲| 欧美日韩国产小视频| 久久av资源网| 日韩午夜视频在线观看| 国产亚洲福利社区一区| 午夜视频一区二区| 美国成人直播| 久久激情五月丁香伊人| 午夜精品久久久| 国产精品亚洲аv天堂网| 欧美91福利在线观看| 国产精品成人aaaaa网站| 亚洲精品三级| 欧美尤物巨大精品爽| 制服丝袜亚洲播放| 欧美jjzz| 毛片基地黄久久久久久天堂| 欧美日韩在线视频首页| 欧美激情综合色| 狠狠色狠狠色综合日日小说| 亚洲专区在线| 国产自产2019最新不卡| 亚洲精选成人| 日韩午夜电影| 欧美成人综合一区| 欧美aⅴ一区二区三区视频| 国产一区在线免费观看| 亚洲欧美bt| 午夜亚洲视频| 国产精品久久久一本精品| 久久国产一区二区| 国产精品女主播| 亚洲小说欧美另类社区| 亚洲视频在线视频| 欧美日韩在线播放三区| 亚洲精品日韩激情在线电影| 亚洲精品国产精品国自产在线| 久久亚裔精品欧美| 牛牛精品成人免费视频| 在线观看中文字幕不卡| 欧美精品福利视频| 亚洲精品网址在线观看| 欧美在线高清| 麻豆freexxxx性91精品| 精品成人国产在线观看男人呻吟| 销魂美女一区二区三区视频在线| 午夜电影亚洲| 国产伦精品一区二区三区四区免费| 久久精品女人天堂| 国产精品自在欧美一区| 亚洲女人天堂成人av在线| 欧美在线一区二区| 国产亚洲一区二区三区| 久久久久高清| 亚洲字幕一区二区| 国产精品白丝av嫩草影院| 亚洲综合大片69999| 久久精品国产99国产精品澳门| 国产亚洲精品福利| 麻豆成人在线播放| 亚洲人成绝费网站色www| 中文在线一区| 国内免费精品永久在线视频| 免费成人黄色av| 99精品黄色片免费大全| 久久精品在线免费观看| 最近看过的日韩成人| 国产精品九九久久久久久久| 久久成人精品| 日韩亚洲国产欧美| 久久影院午夜片一区| 99在线精品视频在线观看| 久久伊人精品天天| 亚洲国产天堂网精品网站| 国产中文一区二区| 欧美国产日产韩国视频| 一区二区激情| 久久午夜电影网| 99亚洲一区二区| 激情成人亚洲| 国产精品播放| 欧美大片免费看| 久久er精品视频| 亚洲丝袜av一区| 亚洲国产精品嫩草影院| 欧美制服丝袜| 亚洲免费视频在线观看| 亚洲激情视频在线播放| 国产欧美午夜| 欧美午夜视频| 欧美区国产区| 欧美国产欧美综合 | 久久精品国产一区二区电影| 亚洲黄色免费电影| 在线免费观看日本欧美| 国产精品www色诱视频| 免费成人在线视频网站| 午夜日韩福利| 在线亚洲精品| 日韩亚洲综合在线| 91久久久一线二线三线品牌| 蜜桃av一区二区| 久久蜜桃精品| 亚洲精品国产拍免费91在线|