1. 程式人生 > >windows執行緒同步的總結

windows執行緒同步的總結

http://blog.csdn.net/peter_teng/article/details/11230525

一 執行緒

1)如果你正在編寫C/C++程式碼,決不應該呼叫CreateThread。相反,應該使用VisualC++執行期庫函式_beginthreadex,退出也應該使用_endthreadex。如果不使用Microsoft的VisualC++編譯器,你的編譯器供應商有它自己的CreateThred替代函式。不管這個替代函式是什麼,你都必須使用。

2)因為_beginthreadex和_endthreadex是CRT執行緒函式,所以必須注意編譯選項runtimelibaray的選擇,使用MT或MTD。

3) _beginthreadex函式的引數列表與CreateThread函式的引數列表是相同的,但是引數名和型別並不完全相同。這是因為Microsoft的C/C++執行期庫的開發小組認為,C/C++執行期函式不應該對Windows資料型別有任何依賴。_beginthreadex函式也像CreateThread那樣,返回新建立的執行緒的控制代碼。

4)下面是關於_beginthreadex的一些要點:

•每個執行緒均獲得由C/C++執行期庫的堆疊分配的自己的tiddata記憶體結構。(tiddata結構位於Mtdll.h檔案中的VisualC++原始碼中)。

•傳遞給_beginthreadex的執行緒函式的地址儲存在tiddata記憶體塊中。傳遞給該函式的引數也儲存在該資料塊中。

•_beginthreadex確實從內部呼叫CreateThread,因為這是作業系統瞭解如何建立新執行緒的唯一方法。

•當呼叫CreatetThread時,它被告知通過呼叫_threadstartex而不是pfnStartAddr來啟動執行新執行緒。還有,傳遞給執行緒函式的引數是tiddata結構而不是pvParam的地址。

•如果一切順利,就會像CreateThread那樣返回執行緒控制代碼。如果任何操作失敗了,便返回NULL。

5) _endthreadex的一些要點:

•C執行期庫的_getptd函式內部呼叫作業系統的TlsGetValue函式,該函式負責檢索呼叫執行緒的tiddata記憶體塊的地址。

•然後該資料塊被釋放,而作業系統的ExitThread函式被呼叫,以便真正撤消該執行緒。當然,退出程式碼要正確地設定和傳遞。

6) 雖然也提供了簡化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

6)執行緒handle因為是核心物件,所以需要在最後close handle。

7)C++主執行緒的終止,同時也會終止所有主執行緒建立的子執行緒,不管子執行緒有沒有執行完畢。

8)如果某執行緒掛起,然後有呼叫WaitForSingleObject等待該執行緒,就會導致死鎖。

二 執行緒同步之Critical Sections

1) 因為Critical Sections不是核心物件,所以只能用來同一程序內執行緒間的同步,不能用來多個不同程序間的執行緒的同步。

2) 如果在Critical Sections中間突然程式crash或是exit而沒有呼叫LeaveCriticalSection,則結果是該執行緒所對應的核心不能被釋放,該執行緒成為死執行緒。

3) 要比其他的核心物件的速度要快。

三 執行緒同步之Mutex
    
1)互斥物件(mutex)核心物件能夠確保執行緒擁有對單個資源的互斥訪問權。實際上互斥物件是因此而得名的。互斥物件包含一個使用數量,一個執行緒ID和一個遞迴計數器。
 2) 互斥物件的行為特性與關鍵程式碼段相同,但是互斥物件屬於核心物件,而關鍵程式碼段則屬於使用者方式物件。這意味著互斥物件的執行速度比關鍵程式碼段要慢。但是這也意味著不同程序中的多個執行緒能夠訪問單個互斥物件,並且這意味著執行緒在等待訪問資源時可以設定一個超時值。

 3) ID用於標識系統中的哪個執行緒當前擁有互斥物件,遞迴計數器用於指明該執行緒擁有互斥物件的次數。

 4) 互斥物件有許多用途,屬於最常用的核心物件之一。通常來說,它們用於保護由多個執行緒訪問的記憶體塊。如果多個執行緒要同時訪問記憶體塊,記憶體塊中的資料就可能遭到破壞。互斥物件能夠保證訪問記憶體塊的任何執行緒擁有對該記憶體塊的獨佔訪問權,這樣就能夠保證資料的完整性。

5)互斥物件的使用規則如下:

• 如果執行緒ID是0(這是個無效ID),互斥物件不被任何執行緒所擁有,並且發出該互斥物件的通知訊號。

• 如果ID是個非0數字,那麼一個執行緒就擁有互斥物件,並且不發出該互斥物件的通知訊號。

• 與所有其他核心物件不同, 互斥物件在作業系統中擁有特殊的程式碼,允許它們違反正常的規則。


四 執行緒同步之Event

1)在所有的核心物件中,事件核心物件是個最基本的物件。它們包含一個使用計數(與所有核心物件一樣),一個用於指明該事件是個自動重置的事件還是一個人工重置的事件的布林值,另一個用於指明該事件處於已通知狀態還是未通知狀態的布林值。

2)事件能夠通知一個操作已經完成。有兩種不同型別的事件物件。一種是人工重置的事件,另一種是自動重置的事件。當人工重置的事件得到通知時,等待該事件的所有執行緒均變為可排程執行緒。當一個自動重置的事件得到通知時,等待該事件的執行緒中只有一個執行緒變為可排程執行緒。

3)當一個執行緒執行初始化操作,然後通知另一個執行緒執行剩餘的操作時,事件使用得最多。事件初始化為未通知狀態,然後,當該執行緒完成它的初始化操作後,它就將事件設定為已通知狀態。這時,一直在等待該事件的另一個執行緒發現該事件已經得到通知,因此它就變成可排程執行緒。

 4)Microsoft為自動重置的事件定義了應該成功等待的副作用規則,即當執行緒成功地等待到該物件時,自動重置的事件就會自動重置到未通知狀態。這就是自動重置的事件如何獲得它們的名字的方法。通常沒有必要為自動重置的事件呼叫ResetEvent函式,因為系統會自動對事件進行重置。但是,Microsoft沒有為人工重置的事件定義成功等待的副作用,所以需要呼叫ResetEvent()。

五 執行緒同步之訊號量(Semaphore)

訊號量(Semaphore)核心物件對執行緒的同步方式與前面幾種方法不同,它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。在用 CreateSemaphore()建立訊號量時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設定為最大資源計數,每增加一個執行緒對共享資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大於0的,就可以發出訊號量訊號。但是當前可用計數減小到0時則說明當前佔用資源的執行緒數已經達到了所允許的最大數目,不能在允許其他執行緒的進入,此時的訊號量訊號將無法發出。執行緒在處理完共享資源後,應在離開的同時通過 ReleaseSemaphore()函式將當前可用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。

使用訊號量核心物件進行執行緒同步主要會用到CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()、 WaitForSingleObject()和WaitForMultipleObjects()等函式。

六 執行緒同步之其他

1)執行緒區域性儲存 (TLS),同一程序中的所有執行緒共享相同的虛擬地址空間。不同的執行緒中的區域性變數有不同的副本,但是static和globl變數是同一程序中的所有執行緒共享的。使用TLS技術可以為static和globl的變數,根據當前程序的執行緒數量建立一個array,每個執行緒可以通過array的index來訪問對應的變數,這樣也就保證了static和global的變數為每一個執行緒都建立不同的副本。

2)互鎖函式的家族十分的龐大,例如InterlockedExchangeAdd()。。。,使用互鎖函式的優點是:他的速度要比其他的CriticalSection,Mutex,Event,Semaphore快很多。

3)等待函式,例如WaitForSingleObject 函式用來檢測 hHandle 事件的訊號狀態,當函式的執行時間超過 dwMilliseconds 就返回,但如果引數 dwMilliseconds 為 INFINITE 時函式將直到相應時間事件變成有訊號狀態才返回,否則就一直等待下去,直到 WaitForSingleObject 有返回直才執行後面的程式碼。

以下是寫的程式碼

CThread.h

  1. #include <process.h>
  2. #include <Windows.h>
  3. //#define  CRITICALSECTION
  4. #define MUTEX
  5. //#define SEMAPHORE
  6. #define EVENT
  7. #ifdef CRITICALSECTION
  8. class CriticalSection  
  9. {  
  10. public:  
  11.     CriticalSection(){ InitializeCriticalSection(&criticalS); }  
  12.     ~CriticalSection(){ DeleteCriticalSection(&criticalS); }  
  13.     void enterCriticalSection(){ EnterCriticalSection(&criticalS); }  
  14.     void leaveCriticalSection(){ LeaveCriticalSection(&criticalS);}  
  15. private:  
  16.     CRITICAL_SECTION criticalS;  
  17. };  
  18. class CLock  
  19. {  
  20. public:  
  21.     CLock(CriticalSection *crs):cs(crs){lock();}  
  22.     ~CLock(){unlock();}  
  23.     void lock(){ cs->enterCriticalSection() ;}  
  24.     void unlock(){ cs->leaveCriticalSection(); }  
  25. private:  
  26.     CriticalSection *cs;   
  27. };  
  28. #endif

CThread.cpp
  1. // CThread.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include "CThread.h"
  5. //#include <Windows.h>
  6. #define MAX1 1
  7. #define MAX2 10
  8. #define INITRESOURCE 10
  9. #define MAXRESOURCE 10
  10. #define THREADNUM 5
  11. #define Thread __declspec(thread)
  12. Thread staticint g_tls = 0;  
  13. int g_count = 0;  
  14. #ifdef CRITICALSECTION
  15.     CriticalSection critSct;  
  16. #endif
  17. #ifdef MUTEX
  18.     HANDLE g_mutex;  
  19. #endif
  20. #ifdef SEMAPHORE 
  21.     HANDLE g_semaphore;  
  22. #endif
  23. #ifdef EVENT
  24.     HANDLE g_event;  
  25. #endif
  26. unsigned _stdcall thread1Entry(void *pList)  
  27. {  
  28. #ifdef CRITICALSECTION
  29.     CLock myLock(&critSct);  
  30. #endif
  31. #ifdef SEMAPHORE
  32.     WaitForSingleObject(g_semaphore, INFINITE);  
  33. #endif
  34. #ifdef MUTEX
  35.     WaitForSingleObject(g_mutex, INFINITE);  
  36. #endif
  37. #ifdef EVENT
  38.     WaitForSingleObject(g_event, INFINITE);  
  39. #endif
  40.     forint i = 0; i < MAX1; i++)  
  41.     {  
  42.         g_count++;  
  43.         printf("threa1:%d\n",g_count);  
  44.     }  
  45. #ifdef EVENT
  46.     SetEvent(g_event);  
  47. #endif
  48.     //if( g_count == 100 )
  49.     //{
  50.         //long preciousCount = 0;
  51.         //ReleaseSemaphore(g_semaphore, 2, &preciousCount);
  52.         //printf("thread precious count is:%d\n", preciousCount);
  53.     //}
  54.     return 0;  
  55. }  
  56. unsigned _stdcall thread2Entry(void *pList)  
  57. {  
  58. #ifdef CRITICALSECTION
  59.         CLock myLock(&critSct);  
  60. #endif
  61. #ifdef MUTEX
  62.         WaitForSingleObject(g_mutex, INFINITE);  
  63. #endif
  64. #ifdef EVENT
  65.         WaitForSingleObject(g_event, INFINITE);  
  66. #endif
  67.     forint i = MAX1; i < MAX2; i++)  
  68.     {  
  69.         g_count++;  
  70.         printf("threa2:%d\n",g_count);  
  71.     }  
  72. #ifdef EVENT
  73.     SetEvent(g_event);  
  74. #endif
  75.     return 0;  
  76. }  
  77. void loadDataIntoMemory()  
  78. {  
  79.     printf("load data into memory!\n");  
  80. }  
  81. int _tmain(int argc, _TCHAR* argv[])  
  82. {  
  83. #ifdef MUTEX
  84.     g_mutex = CreateMutex(NULL, false, NULL);  
  85.     if( g_mutex == NULL )  
  86.     {  
  87.         printf("create mutex failed with error %d\n", GetLastError());  
  88.         return 1;  
  89.     }  
  90. #endif
  91. #ifdef SEMAPHORE
  92.     g_semaphore = CreateSemaphore(NULL, INITRESOURCE, MAXRESOURCE, NULL);  
  93. #endif
  94. #ifdef EVENT
  95.     g_event = CreateEvent(NULL, falsefalse, NULL);  
  96. #endif
  97.     HANDLEthread[THREADNUM + 1];  
  98.     forint i = 0; i < THREADNUM; i++ )  
  99.     {  
  100.         thread[i] = (HANDLE)_beginthreadex(NULL, 0, thread1Entry, NULL, 0, NULL);  
  101.         ifthread[i] == NULL )  
  102.         {  
  103.             printf("create thread failed with error %d\n", GetLastError());  
  104.             return 1;  
  105.         }  
  106.     }  
  107. #ifdef EVENT
  108. 相關推薦

    windows執行同步總結

    http://blog.csdn.net/peter_teng/article/details/11230525 一 執行緒 1)如果你正在編寫C/C++程式碼,決不應該呼叫CreateThread。相反,應該使用VisualC++執行期庫函式_beginthread

    秒殺多執行第九篇 經典執行同步總結 關鍵段 事件 互斥量 訊號量

                    前面《秒殺多執行緒第四篇一個經典的多執行緒同步問題》提出了一個經典的多執行緒同步互斥問題,這個問題包括了主執行緒與子執行緒的同步,子執行緒間的互斥,是一道非常經典的多執行緒同步互斥問題範例,後面分別用了四篇來詳細介紹常用的執行緒同步互斥機制——關鍵段、事件、互斥量、訊號量。下面

    Windows執行同步之互斥鎖(Mutex)

    執行緒同步的方式和機制臨界區、互斥區、事件、訊號量四種方式臨界區(Critical Section)、互斥量(Mutex)、訊號量(Semaphore)、事件(Event)的區別1、臨界區:通過對多執行緒的序列化來訪問公共資源或一段程式碼,速度快,適合控制資料訪問。在任意時刻

    執行同步總結--臨界區 事件 互斥量 訊號量

    在WIN32中,同步機制主要有以下幾種: 臨界區(Critical section) 事件(Event); 互斥量(mutex); 訊號量(semaphore);   臨界區(Critical section) 臨界區(Cri

    windows 執行同步的4種方法

    1. 互斥訊號量  #include <windows.h> #include <iostream>usingnamespace std; DWORD WINAPI Fun1Proc(LPVOID param); DWORD WINAPI Fun

    Windows執行同步的方法

    Summary: 對於多執行緒程式設計,一個很重要的問題就是解決由資料共享引起的資料競爭的問題,通過一定的執行緒同步的方法能避免資料競爭。在Win32多執行緒中,同步方法包括使用者態同步方式:InterLock、CriticalSection、SRWLock和核心態同步方式:Event、Semaphore、

    windows執行同步機制摘要

    執行緒之間的同步使用一些核心物件:如thread,  process, evnet, mutex, semaphore. 線上程之間使用等待函式如WaitForSingleObjects,  WaitForMultipleObjects. 等待函式使用核心物件的handle作

    Windows執行漫談——.NET執行同步之Interlocked和ReadWrite鎖

    摘要: 本系列意在記錄Windwos執行緒的相關知識點,包括執行緒基礎、執行緒排程、執行緒同步、TLS、執行緒池等。 這篇來說說靜態的Interlocked類和ReadWrite鎖 .NET中的Interlock

    Windows程式設計之執行同步

    Windows程式設計中執行緒同步的主要機制:互斥、事件、訊號量、可等待定時器,不說了,直接上程式碼: // ThreadSync.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <windows.h>

    Windows原理】執行同步-訊號量

    #include "stdafx.h" #include <windows.h> int g_num = 0; HANDLE g_hSemaphore = nullptr; DWORD WINAPI ThreadProc(LPVOID lpParam) { for

    Windows原理】執行同步-事件物件2

    #include "stdafx.h" #include <windows.h> HANDLE g_hEventA = nullptr; // 三個只讀執行緒 DWORD WINAPI ThreadProcA(LPVOID lpParam) { WaitForSin

    Windows原理】執行同步-事件物件

    #include "stdafx.h" #include <windows.h> HANDLE g_hEventA = nullptr; HANDLE g_hEventB = nullptr; DWORD WINAPI ThreadProcA(LPVOID lpParam) {

    執行同步(windows平臺):事件

    一:介紹 事件Event實際上是個核心物件,事件分兩種狀態:激發狀態和未激發狀態。分兩種型別:手動處置事件和自動處置事件。 手動處置事件被設定為激發狀態後,會喚醒所有等待的執行緒,一直保持為激發狀態,

    JAVA多執行機制第四彈:(末篇)執行常用方法總結執行同步

    執行緒的常用方法: 這裡我覺得這個老師的教案總結的很舒胡(主要是懶~):  執行緒同步: 在處理多執行緒問題時,有一個Bug問題啊:當兩個或多個執行緒同時訪問一個父類變數時,並且一個執行緒需要修改這個變數,(一個執行緒讓變數A增加,另一個執行緒讓變數A減少)。 所

    執行同步相關術語總結

    對於初次接觸執行緒同步的前端來說,總是對互斥鎖、條件變數、訊號量等術語傻傻分不清楚,這裡根據自己的理解簡單做下總結,如有疏漏之處,歡迎大家批評指正。 互斥鎖 在多執行緒環境中往往存在因某一資源被同時訪問導致該資源不一致的問題,互斥鎖 通過排它性,即同時只允許一個訪問者對其進行訪問來保證資源的有效同步,但它

    Windows執行(七)使用互斥量無法解決執行同步問題

    互斥量介面: 1.建立互斥量: HANDLE CreateMutex ( LPSECURITY_ATTRIBUTES lpMutexAttributes,//安全控制,一般為NULL BOOL bInitialOwner, //

    Windows執行(六)使用事件機制解決執行同步問題

    事件相關函式: 1.建立事件:CreateEvent HANDLE CreateEvent ( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,

    Windows執行(五)關鍵段無法解決執行同步問題

    關鍵段: 關鍵段型別CRITICAL_SECTION 1.初始化關鍵段: void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 2.銷燬關鍵段: void DeleleCriticalSe

    Windows執行(四)執行同步與互斥問題

    執行緒同步與互斥的測試函式如下所示: #include <stdio.h> #include <process.h> #include <Windows.h> #define THREAD_NUM 10 unsigned long g_nNum

    Java基礎學習之執行同步方法總結

            引入執行緒同步的原因:當有多個執行緒要同時訪問一個變數或物件時,如果這些執行緒中既有讀又有寫操作時,就會導致變數值或物件的狀態出現混亂,從而導致程式異常,使用者也得不到想要的結果。比如,如果一個銀行賬戶同時被兩個執行緒操作,一個取100塊,一個