本文共 5649 字,大约阅读时间需要 18 分钟。
首选使用临界区对象,主要原因是使用简单。 EnterCriticalSection()函数等候指定的危险区段对象的所有权。当调用的线程被允许所有权时,函数返回。 EnterCriticalSection (),一个单独进程的线程可以使用一个危险区段对象作为相互-排除同步。 进程负责分配被一个危险区段对象使用的内存, 它藉由声明一个CRITICAL_SECTION类型 的变量实现。在使用一个危险区段之前,进程的一些线程必须调用 InitializeCriticalSection 函数设定对象的初值.为了要使互斥的访问被共享的资源,每个线程调用EnterCriticalSection 或者 TryEnterCriticalSection 功能,在执行访问被保护资源的任何代码段之前,请求危险区段的所有权。 #include <windows.h>#include <iostream> using namespace std; DWORD WINAPI Fun1Proc(LPVOID lpParameter); DWORD WINAPI Fun2Proc(LPVOID lpParameter); int tickets=100; CRITICAL_SECTION g_csA; CRITICAL_SECTION g_csB; void main() { HANDLE hThread1; HANDLE hThread2; hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); InitializeCriticalSection(&g_csA); InitializeCriticalSection(&g_csB); Sleep(40000); DeleteCriticalSection(&g_csA); DeleteCriticalSection(&g_csB); } DWORD WINAPI Fun1Proc(LPVOID lpParameter) { while (TRUE) { EnterCriticalSection(&g_csA); Sleep(1); //EnterCriticalSection(&g_csB);//临界区的同步和互锁 if (tickets>0) { Sleep(1); cout<<"Thread1 sell ticket :"<<tickets--<<endl; //LeaveCriticalSection(&g_csB); LeaveCriticalSection(&g_csA); } else { //LeaveCriticalSection(&g_csB); LeaveCriticalSection(&g_csA); break; } } return 0; } DWORD WINAPI Fun2Proc(LPVOID lpParameter) { while (TRUE) { EnterCriticalSection(&g_csB); Sleep(1); EnterCriticalSection(&g_csA); if (tickets>0) { Sleep(1); cout<<"Thread2 sell ticket :"<<tickets--<<endl; LeaveCriticalSection(&g_csA); LeaveCriticalSection(&g_csB); } else { LeaveCriticalSection(&g_csA); LeaveCriticalSection(&g_csB); break; } } return 0; } --------------------------------------------------------------------------------
二、使用互斥对象 DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); 如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUTWaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。#include <windows.h> #include <iostream> using namespace std; DWORD WINAPI Fun1Proc(LPVOID lpParameter); DWORD WINAPI Fun2Proc(LPVOID lpParameter); int index =0; int tickets=100; HANDLE hMutex; void main() { HANDLE hThread1; HANDLE hThread2; //创建线程 hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); //************************************************************** //保证应用程序只有一个实例运行,创建一个命名的互斥对象. hMutex=CreateMutex(NULL,TRUE,LPCTSTR("tickets")); //创建时主线程拥有该互斥对象,互斥对象的线程ID为主线程的ID,同时将该互斥对象内部计数器置为1 if (hMutex) { if (ERROR_ALREADY_EXISTS==GetLastError()) { cout<<"only one instance can run!"<<endl; //Sleep(40000); return; } } //************************************************************** WaitForSingleObject(hMutex,INFINITE); //使用该函数请求互斥对象时,虽说该对象处于无信号状态,但因为请求的线程ID和该互斥对象所有者的线程ID是相同的.所以仍然可以请求到这个互斥对象,于是该互斥对象内部计数器加1,内部计数器的值为2. 意思是有两个等待动作 ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值递减1,操作系统不会将这个互斥对象变为已通知状态. ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值为0,同时将该对象设置为已通知状态. //对于互斥对象来说,谁拥有谁释放 Sleep(40000); } DWORD WINAPI Fun1Proc(LPVOID lpParameter) { while (TRUE) { WaitForSingleObject(hMutex,INFINITE);//等待互斥对象有信号 if (tickets>0) { Sleep(1); cout<<"thread1 sell ticket :"<<tickets--<<endl; } else break; ReleaseMutex(hMutex);//设置该互斥对象的线程ID为0,并且将该对象设置为有信号状态 } return 0; } DWORD WINAPI Fun2Proc(LPVOID lpParameter) { while (TRUE) { WaitForSingleObject(hMutex,INFINITE); if (tickets>0) { Sleep(1); cout<<"thread2 sell ticket :"<<tickets--<<endl; } else break; ReleaseMutex(hMutex); } return 0;
三、使用事件对象 HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD BOOL bManualReset, // reset type BOOL bInitialState, // initial state LPCTSTR lpName // object name ); 该函数创建一个Event同步对象,并返回该对象的Handle lpEventAttributes 一般为NULL bManualReset 创建的Event是自动复位还是人工复位 ,如果true,人工复位, 一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复 为无信号. 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时, 该Event就会自动复位,变成无信号. bInitialState 初始状态,true,有信号,false无信号 lpName Event对象名 一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle() 来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent() 来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待 其变为有信号. PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event 对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的. 对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于 人工复位的Event对象,它释放所有等待的thread.#include <windows.h> #include <iostream>using namespace std;DWORD WINAPI Fun1Proc(LPVOID lpParameter);DWORD WINAPI Fun2Proc(LPVOID lpParameter);int tickets=100;HANDLE g_hEvent;void main() { HANDLE hThread1;HANDLE hThread2;//**************************************************//创建一个命名的自动重置事件内核对象g_hEvent=CreateEvent(NULL,FALSE,FALSE,LPCTSTR("tickets"));if (g_hEvent){ if (ERROR_ALREADY_EXISTS==GetLastError()){ cout<<"only one instance can run!"<<endl; return;}}//**************************************************SetEvent(g_hEvent);//创建线程hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);Sleep(40000); //关闭事件对象句柄CloseHandle(g_hEvent);}DWORD WINAPI Fun1Proc(LPVOID lpParameter) { while (TRUE){ WaitForSingleObject(g_hEvent,INFINITE);//ResetEvent(g_hEvent);if (tickets>0){ Sleep(1); cout<<"thread1 sell ticket :"<<tickets--<<endl; SetEvent(g_hEvent);}else{ SetEvent(g_hEvent); break;}}return 0;}DWORD WINAPI Fun2Proc(LPVOID lpParameter) { while (TRUE){ WaitForSingleObject(g_hEvent,INFINITE);//ResetEvent(g_hEvent);if (tickets>0){ cout<<"Thread2 sell ticket :"<<tickets--<<endl; SetEvent(g_hEvent);}else{ SetEvent(g_hEvent); break;}}return 0; |
转载地址:http://yisqi.baihongyu.com/