windows編程之多線程總結

來源:互聯網
上載者:User

用於線程互斥的方法有:原子鎖,關鍵地區(CriticalSection),互斥量(Mutex),。

用於線程同步的方法有:事件(Event),訊號量(Semaphore),定時器(這裡我們不談)。

原子鎖:我們都知道簡單的i++,並不是原子操作,在內部其實分了幾步來做,在這種情況下使用多線程就會出問題。所以我們可以採用原子鎖,但是這種方法有一定的局限性,那就是只能是執行加減的簡單資料的操作,如果涉及到複雜的資料結構,那麼就會出問題。

InterlockedIncrement(LONG volatile*Addend);

InterlockedDecrement(LONG volatile*Addend);

InterlockedExchangeAdd(LONG volatile*Addend,
LONGValue);

InterlockedExchange(LONG volatile*Target,
LONGValue);

例子:

沒有使用原子鎖的情況:

#include <stdio.h>#include <windows.h>#include <process.h>volatile long g_nLoginCount; unsigned int __stdcall Fun(void *pPM); const DWORD THREAD_NUM = 50;unsigned int __stdcall ThreadFun(void *pPM){g_nLoginCount++;return 0;}int main(){int num= 20;while (num--){g_nLoginCount = 0;int i;HANDLE  handle[THREAD_NUM];for (i = 0; i < THREAD_NUM; i++)handle[i] = (HANDLE )_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);for(i=0;i<THREAD_NUM;i++){CloseHandle(handle[i]);}printf("%d個線程執行i++,結果是%d\n", THREAD_NUM, g_nLoginCount);}return 0;}

這裡解釋下為什麼搞幾個線程,還弄的這麼複雜,一個while迴圈,一個for迴圈,這是因為不能一次建立很多線程,否則會出問題,你自己可以試試依次性建立100個線程試試,會出問題的。貌似一次最多隻能建立64個線程。所以這裡採用了這麼複雜的方法。

使用原子鎖的情況:

unsigned int __stdcall ThreadFun(void *pPM){g_nLoginCount++;InterlockedIncrement(&g_nLoginCount);return 0;}


關鍵地區(CriticalSection)一般線程互斥用的多的是這種情況。

void
InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); -----------初始化關鍵地區

void
DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);    -----------刪除關鍵地區

void
EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);     -----------進入關鍵地區void
LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);    -----------退出關鍵地區

一般錯誤的情況:

#include <stdio.h>#include <process.h>#include <windows.h>long g_nNum;unsigned int __stdcall Fun(void *pPM);const int THREAD_NUM = 10;int main(){HANDLE  handle[THREAD_NUM];g_nNum = 0;int i = 0;while (i < THREAD_NUM) {handle[i++] = (HANDLE)_beginthreadex(NULL, 0, Fun, NULL, 0, NULL);}WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);for(i=0;i<sizeof(handle);i++){CloseHandle(handle[i]);}return 0;}unsigned int __stdcall Fun(void *pPM){Sleep(50);g_nNum++;Sleep(0);printf("當前計數為:%d\n",g_nNum);return 0;}

當使用了關鍵地區的情況:

CRITICAL_SECTION g_csThreadCode;InitializeCriticalSection(&g_csThreadCode);DeleteCriticalSection(&g_csThreadCode);
unsigned int __stdcall Fun(void *pPM){Sleep(50);EnterCriticalSection(&g_csThreadCode);g_nNum++;Sleep(0);printf("當前計數為:%d\n",g_nNum);LeaveCriticalSection(&g_csThreadCode);return 0;}

事件(Event)

HANDLECreateEvent(

 LPSECURITY_ATTRIBUTESlpEventAttributes,

 BOOLbManualReset,

 BOOLbInitialState,

 LPCTSTRlpName

);---------建立事件。

HANDLEOpenEvent(

 DWORDdwDesiredAccess,

 BOOLbInheritHandle,

 LPCTSTRlpName     

);------------開啟事件

BOOLSetEvent(HANDLEhEvent);----------觸發事件

BOOLResetEvent(HANDLEhEvent);-----------將事件設為未觸發


一般事件分成兩種:手動置位事件(TRUE)和自動置位事件(FALSE),這是在CreateEvent函數的第二個參數指定的。它們的區別是:手動置位事件當調用SetEvent後,所有等待這個事件的線程啟用,而自動置位事件調用SetEvent後,只有一個線程被啟用。自動置位事件不用調用ResetEvent函數,因為系統會自動幫你置為未觸發,而手動置位事件還要調用ResetEvent函數。


在展示事件之前,我們先來說說線程互斥和線程同步之間的區別吧。我的理解是:線程互斥是相當於兩個寫者同時去寫一個檔案,造成的混亂;線程同步相當於當有讀者在讀檔案的時候,寫者還在不停的寫造成的混亂。在以前的基礎上,我們把線程ID傳進去。(主線程去寫,子線程去讀)。
沒有用事件的情況:
#include <stdio.h>#include <process.h>#include <windows.h>long g_nNum;unsigned int __stdcall Fun(void *pPM);const int THREAD_NUM = 10;CRITICAL_SECTION g_csThreadCode;int main(){InitializeCriticalSection(&g_csThreadCode);HANDLE  handle[THREAD_NUM];g_nNum = 0;int i = 0;while (i < THREAD_NUM) {handle[i++] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);}WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);for(i=0;i<sizeof(handle);i++){CloseHandle(handle[i]);}DeleteCriticalSection(&g_csThreadCode);return 0;}unsigned int __stdcall Fun(void *pPM){int nThreadNum = *(int *)pPM; Sleep(50);EnterCriticalSection(&g_csThreadCode);g_nNum++;Sleep(0);printf("當前線程為:%d,當前計數為:%d\n",nThreadNum,g_nNum);LeaveCriticalSection(&g_csThreadCode);return 0;}

線程ID不符合要求。。
使用事件的情況:(下面這裡用的是手動設定事件,所以要調用ResetEvent)。

#include <stdio.h>#include <process.h>#include <windows.h>long g_nNum;unsigned int __stdcall Fun(void *pPM);const int THREAD_NUM = 10;HANDLE  g_hThreadEvent;CRITICAL_SECTION g_csThreadCode;int main(){g_hThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); InitializeCriticalSection(&g_csThreadCode);HANDLE  handle[THREAD_NUM];g_nNum = 0;int i = 0;while (i < THREAD_NUM) {handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);WaitForSingleObject(g_hThreadEvent, INFINITE); ResetEvent(g_hThreadEvent);i++;}WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);for(i=0;i<sizeof(handle);i++){CloseHandle(handle[i]);}CloseHandle(g_hThreadEvent);DeleteCriticalSection(&g_csThreadCode);return 0;}unsigned int __stdcall Fun(void *pPM){int nThreadNum = *(int *)pPM; SetEvent(g_hThreadEvent);Sleep(50);EnterCriticalSection(&g_csThreadCode);g_nNum++;Sleep(0);printf("當前線程為:%d,當前計數為:%d\n",nThreadNum,g_nNum);LeaveCriticalSection(&g_csThreadCode);return 0;}

線程ID符合要求。。

互斥量
#include <stdio.h>#include <process.h>#include <windows.h>long g_nNum;unsigned int __stdcall Fun(void *pPM);const int THREAD_NUM = 10;HANDLE  g_mutex;int main(){g_mutex = CreateMutex(NULL, FALSE, NULL);HANDLE  handle[THREAD_NUM];g_nNum = 0;int i = 0;while (i < THREAD_NUM) {handle[i++] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); }WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);CloseHandle(g_mutex);for (i = 0; i < THREAD_NUM; i++)CloseHandle(handle[i]);return 0;}unsigned int __stdcall Fun(void *pPM){Sleep(50);WaitForSingleObject(g_mutex,INFINITE);g_nNum++;Sleep(0);printf("當前計數為:%d\n",g_nNum);ReleaseMutex(g_mutex);return 0;}

訊號量(Semaphore)

HANDLE
CreateSemaphore(

 
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

 
LONG lInitialCount,

 
LONG lMaximumCount,

 
LPCTSTR lpName

);------------------建立訊號量

HANDLE
OpenSemaphore(

 
DWORD dwDesiredAccess,

 
BOOL bInheritHandle,

 
LPCTSTR lpName

);------------------開啟訊號量

BOOL
ReleaseSemaphore(

 
HANDLE hSemaphore,

 
LONG lReleaseCount,  

 
LPLONG lpPreviousCount 

);--------------------釋放訊號量

訊號量的增:ReleaseSemaphore。訊號量的減:WaitForSingleObject(..);當請求訊號量時,如果當前訊號量為0即不觸發狀態,那麼線程進入阻塞狀態,直到訊號量值>0,該函數才返回,線程進入可調度狀態,同時訊號量值減一。

注意:訊號量的值不可能小於0。

#include <stdio.h>#include <process.h>#include <windows.h>long g_nNum;unsigned int __stdcall Fun(void *pPM);const int THREAD_NUM = 10;HANDLE            g_Semaphore;CRITICAL_SECTION  g_CriticalSection;int main(){g_Semaphore = CreateSemaphore(NULL, 0, 1, NULL);InitializeCriticalSection(&g_CriticalSection);HANDLE  handle[THREAD_NUM];g_nNum = 0;int i = 0;while (i < THREAD_NUM) {handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);WaitForSingleObject(g_Semaphore, INFINITE);++i;}WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);DeleteCriticalSection(&g_CriticalSection);CloseHandle(g_Semaphore);for (i = 0; i < THREAD_NUM; i++)CloseHandle(handle[i]);return 0;}unsigned int __stdcall Fun(void *pPM){int nThreadNum = *(int *)pPM;ReleaseSemaphore(g_Semaphore, 1, NULL);Sleep(50);EnterCriticalSection(&g_CriticalSection);++g_nNum;Sleep(0);printf("當前線程為:%d,當前計數為:%d\n",nThreadNum,g_nNum);LeaveCriticalSection(&g_CriticalSection);return 0;}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.