windows编程之多线程总结

来源:互联网 发布:少儿英语教学知乎 编辑:程序博客网 时间:2024/04/30 00:50

用于线程互斥的方法有:原子锁,关键区域(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)

一般线程互斥用的多的是这种情况。

voidInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); -----------初始化关键区域

voidDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);    -----------删除关键区域

void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);     -----------进入关键区域
voidLeaveCriticalSection(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)

HANDLECreateSemaphore(

 LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

 LONG lInitialCount,

 LONG lMaximumCount,

 LPCTSTR lpName

);------------------创建信号量

HANDLEOpenSemaphore(

 DWORD dwDesiredAccess,

 BOOL bInheritHandle,

 LPCTSTR lpName

);------------------打开信号量

BOOLReleaseSemaphore(

 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;}


原创粉丝点击