BOOL SetThreadPriority(HANDLE hThread, int nPriority); |
![]() |
![]() |
HANDLE hCurrentThread = GetCurrentThread(); //获得该线E句?br />SetThreadPriority(hCurrentThread, THREAD_PRIORITY_LOWEST); |
VOID Sleep(DWORD dwMilliseconds); |
Int GetThreadPriority (HANDLE hThread); |
BOOL WINAPI GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); |
获得/讄U程上下?br />BOOL WINAPI GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); BOOL WINAPI SetThreadContext( HANDLE hThread, CONST CONTEXT *lpContext ); |
#define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <stdlib.h> #include <windows.h> #include <conio.h> DWORD WINAPI ThreadFunc(LPVOID); int main() { HANDLE hThrd1; HANDLE hThrd2; DWORD exitCode1 = 0; DWORD exitCode2 = 0; DWORD threadId; hThrd1 = CreateThread(NULL, 0, ThreadFunc, (LPVOID)1, 0, &threadId ); if (hThrd1) printf("Thread 1 launched\n"); hThrd2 = CreateThread(NULL, 0, ThreadFunc, (LPVOID)2, 0, &threadId ); if (hThrd2) printf("Thread 2 launched\n"); // Keep waiting until both calls to GetExitCodeThread succeed AND // neither of them returns STILL_ACTIVE. for (;;) { printf("Press any key to exit..\n"); getch(); GetExitCodeThread(hThrd1, &exitCode1); GetExitCodeThread(hThrd2, &exitCode2); if ( exitCode1 == STILL_ACTIVE ) puts("Thread 1 is still running!"); if ( exitCode2 == STILL_ACTIVE ) puts("Thread 2 is still running!"); if ( exitCode1 != STILL_ACTIVE && exitCode2 != STILL_ACTIVE ) break; } CloseHandle(hThrd1); CloseHandle(hThrd2); printf("Thread 1 returned %d\n", exitCode1); printf("Thread 2 returned %d\n", exitCode2); return EXIT_SUCCESS; } /* * Take the startup value, do some simple math on it, * and return the calculated value. */ DWORD WINAPI ThreadFunc(LPVOID n) { Sleep((DWORD)n*1000*2); return (DWORD)n * 10; } |
#define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <stdlib.h> #include <windows.h> DWORD WINAPI ThreadFunc(LPVOID); int main() { HANDLE hThrd; DWORD threadId; int i; for (i = 0; i < 5; i++) { hThrd = CreateThread(NULL, 0, ThreadFunc, (LPVOID)i, 0, &threadId); if (hThrd) { printf("Thread launched %d\n", i); CloseHandle(hThrd); } } // Wait for the threads to complete. Sleep(2000); return EXIT_SUCCESS; } DWORD WINAPI ThreadFunc(LPVOID n) { int i; for (i = 0; i < 10; i++) printf("%d%d%d%d%d%d%d%d\n", n, n, n, n, n, n, n, n); return 0; } |
![]() ![]() ![]() |
#include <Win32.h> #include <stdio.h> #include <process.h> unsigned Counter; unsigned __stdcall SecondThreadFunc(void *pArguments) { printf("In second thread...\n"); while (Counter < 1000000) Counter++; _endthreadex(0); return 0; } int main() { HANDLE hThread; unsigned threadID; printf("Creating second thread...\n"); // Create the second thread. hThread = (HANDLE)_beginthreadex(NULL, 0, &SecondThreadFunc, NULL, 0, &threadID); // Wait until second thread terminates WaitForSingleObject(hThread, INFINITE); printf("Counter should be 1000000; it is-> %d\n", Counter); // Destroy the thread object. CloseHandle(hThread); } |
UINT ThreadFunction(LPVOID pParam) { //U程处理代码 return0; } |
while(1) { WaitForSingleObject(??;//或WaitForMultipleObjects(? //Do something } |
#include "windows.h" #include <process.h> class ExampleTask { public: void taskmain(LPVOID param); void StartTask(); }; void ExampleTask::taskmain(LPVOID param) {} void ExampleTask::StartTask() { _beginthread(taskmain,0,NULL); } int main(int argc, char* argv[]) { ExampleTask realTimeTask; realTimeTask.StartTask(); return 0; } |
error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)' None of the functions with this name in scope match the target type |
#include "windows.h" #include <process.h> class ExampleTask { public: void taskmain(LPVOID param); }; void ExampleTask::taskmain(LPVOID param) {} int main(int argc, char* argv[]) { ExampleTask realTimeTask; _beginthread(ExampleTask::taskmain,0,NULL); return 0; } |
error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)' None of the functions with this name in scope match the target type |
#include "windows.h" #include <process.h> class ExampleTask { public: void static taskmain(LPVOID param); void StartTask(); }; void ExampleTask::taskmain(LPVOID param) {} void ExampleTask::StartTask() { _beginthread(taskmain,0,NULL); } int main(int argc, char* argv[]) { ExampleTask realTimeTask; realTimeTask.StartTask(); return 0; } ?br />#include "windows.h" #include <process.h> class ExampleTask { public: void static taskmain(LPVOID param); }; void ExampleTask::taskmain(LPVOID param) {} int main(int argc, char* argv[]) { _beginthread(ExampleTask::taskmain,0,NULL); return 0; } |
#include "windows.h" #include <process.h> class ExampleTask { public: friend void taskmain(LPVOID param); void StartTask(); }; void taskmain(LPVOID param) { ExampleTask * pTaskMain = (ExampleTask *) param; //通过pTaskMain指针引用 } void ExampleTask::StartTask() { _beginthread(taskmain,0,this); } int main(int argc, char* argv[]) { ExampleTask realTimeTask; realTimeTask.StartTask(); return 0; } |
HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,//Pointer to a SECURITY_ATTRIBUTES structure SIZE_T dwStackSize, //Initial size of the stack, in bytes. LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, //Pointer to a variable to be passed to the thread DWORD dwCreationFlags, //Flags that control the creation of the thread LPDWORD lpThreadId //Pointer to a variable that receives the thread identifier ); |
uintptr_t _beginthread( void( __cdecl *start_address )( void * ), //Start address of routine that begins execution of new thread unsigned stack_size, //Stack size for new thread or 0. void *arglist //Argument list to be passed to new thread or NULL ); uintptr_t _beginthreadex( void *security,//Pointer to a SECURITY_ATTRIBUTES structure unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag,//Initial state of new thread (0 for running or CREATE_SUSPENDED for suspended); unsigned *thrdaddr ); |
VOID ExitThread(UINT fuExitCode ); |
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode); |
DWORD ResumeThread(HANDLE hThread); |
DWORD SuspendThread(HANDLE hThread); |
HANDLE CreateSemaphore ( PSECURITY_ATTRIBUTE psa, LONG lInitialCount, //开始时可供使用的资源数 LONG lMaximumCount, //最大资源数 PCTSTR pszName); |
BOOL WINAPI ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, //信号量的当前资源数增加lReleaseCount LPLONG lpPreviousCount ); |
HANDLE OpenSemaphore ( DWORD fdwAccess, BOOL bInherithandle, PCTSTR pszName ); |
int globalVar = 0; DWORD WINAPI ThreadFunc1(LPVOID n) { globalVar++; return 0; } DWORD WINAPI ThreadFunc2(LPVOID n) { globalVar++; return 0; } |
00401038 mov eax,[globalVar (0042d3f0)] 0040103D add eax,1 00401040 mov [globalVar (0042d3f0)],eax |
int globalVar = 0; DWORD WINAPI ThreadFunc1(LPVOID n) { InterlockedExchangeAdd(&globalVar,1); return 0; } DWORD WINAPI ThreadFunc2(LPVOID n) { InterlockedExchangeAdd(&globalVar,1); return 0; } |
HANDLE CreateWaitableTimer( PSECURITY_ATTRISUTES psa, BOOL fManualReset,//人工重置或自动重|定时器 PCTSTR pszName); |
BOOL SetWaitableTimer( HANDLE hTimer, //要设|的定时?BR> const LARGE_INTEGER *pDueTime, //指明定时器第一ơ激zȝ旉 LONG lPeriod, //指明此后定时器应该间隔多长时间激zM?BR> PTIMERAPCROUTINE pfnCompletionRoutine, PVOID PvArgToCompletionRoutine, BOOL fResume); |
BOOl Cancel WaitableTimer( HANDLE hTimer //要取消的定时?BR>); |
HANDLE OpenWaitableTimer ( DWORD fdwAccess, BOOL bInherithandle, PCTSTR pszName ); |
#include <Windows.h> #include <stdio.h> CRITICAL_SECTION cs1, cs2; long WINAPI ThreadFn(long); main() { long iThreadID; InitializeCriticalSection(&cs1); InitializeCriticalSection(&cs2); CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFn, NULL, 0,&iThreadID)); while (TRUE) { EnterCriticalSection(&cs1); printf("\nU程1占用临界?"); EnterCriticalSection(&cs2); printf("\nU程1占用临界?"); printf("\nU程1占用两个临界?); LeaveCriticalSection(&cs2); LeaveCriticalSection(&cs1); printf("\nU程1释放两个临界?); Sleep(20); }; return (0); } long WINAPI ThreadFn(long lParam) { while (TRUE) { EnterCriticalSection(&cs2); printf("\nU程2占用临界?"); EnterCriticalSection(&cs1); printf("\nU程2占用临界?"); printf("\nU程2占用两个临界?); LeaveCriticalSection(&cs1); LeaveCriticalSection(&cs2); printf("\nU程2释放两个临界?); Sleep(20); }; } |
long WINAPI ThreadFn(long lParam) { while (TRUE) { EnterCriticalSection(&cs1); printf("\nU程2占用临界?"); EnterCriticalSection(&cs2); printf("\nU程2占用临界?"); printf("\nU程2占用两个临界?); LeaveCriticalSection(&cs1); LeaveCriticalSection(&cs2); printf("\nU程2释放两个临界?); Sleep(20); }; } |
CRITICAL_SECTION gCriticalSection; |
VOID WINAPI InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection //指向E序员定义的CRITICAL_SECTION变量 ); |
VOID WINAPI DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection //指向一个不再需要的CRITICAL_SECTION变量 ); |
VOID WINAPI EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection //指向一个你卛_锁定的CRITICAL_SECTION变量 ); |
VOID WINAPI LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection //指向一个你卛_d的CRITICAL_SECTION变量 ); |
void UpdateData() { EnterCriticalSection(&gCriticalSection); ...//do something LeaveCriticalSection(&gCriticalSection); } |
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性结构指针,可ؓNULL BOOL bInitialOwner, //是否占有该互斥量QTRUEQ占有,FALSEQ不占有 LPCTSTR lpName //信号量的名称 ); |
HANDLE hMutex; hMutex = OpenMutex(MUTEX_ALL_Access, FALSE, L"mutexName"); if (hMutex){ ? ?BR>else{ ?BR>} |
BOOL WINAPI ReleaseMutex( HANDLE hMutex ); |
void UpdateResource() { WaitForSingleObject(hMutex,?; ...//do something ReleaseMutex(hMutex); } |
![]() |
int var; //全局变量 UINT ThreadFunction(LPVOIDpParam) { var = 0; while (var < MaxValue) { //U程处理 ::InterlockedIncrement(long*) &var); } return 0; } L下列E序Q?BR>int globalFlag = false; DWORD WINAPI ThreadFunc(LPVOID n) { Sleep(2000); globalFlag = true; return 0; } int main() { HANDLE hThrd; DWORD threadId; hThrd = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &threadId); if (hThrd) { printf("Thread launched\n"); CloseHandle(hThrd); } while (!globalFlag) ; printf("exit\n"); } |
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTESl构指针Q可为NULL BOOL bManualReset, // 手动/自动 // TRUEQ在WaitForSingleObject后必L动调用ResetEvent清除信号 // FALSEQ在WaitForSingleObject后,pȝ自动清除事g信号 BOOL bInitialState, //初始状?BR> LPCTSTR lpName //事g的名U?BR>); |
HANDLE hEvent=OpenEvent(EVENT_ALL_Access,true,"MyEvent"); ResetEvent(hEvent); |
QdaQ]当前行的Windows操作pȝQ它能同时运行几个程?独立q行的程序又UCE?Q对于同一个程序,它又可以分成若干个独立的执行,我们UC为线E,U程提供了多d处理的能力。用q程和线E的观点来研IY件是当今普遍采用的方法,q程和线E的概念的出玎ͼҎ高Y件的q行性有着重要的意义。现在的应用软g无一不是多线E多d处理Q单U城的Y件是不可惌的。因此掌握多U程多Q务设计方法对每个E序员都是必需要掌握的。本文针对多U程技术在应用中经帔R到的问题Q如U程间的通信、同步等Q对它们分别q行探讨? 一?理解U程 要讲解线E,不得不说一下进E,q程是应用程序的执行实例Q每个进E是q有的虚拟地址I间、代码、数据和其它pȝ资源l成。进E在q行时创建的资源随着q程的终止而死亡。线E的基本思想很简单,它是一个独立的执行,是进E内部的一个独立的执行单元Q相当于一个子E序Q它对应Visual C++中的CwinThreadcȝ对象。单独一个执行程序运行时Q缺省的q行包含的一个主U程Q主U程以函数地址的Ş式,如main或WinMain函数Q提供程序的启动点,当主U程l止Ӟq程也随之终止,但根据需要,应用E序又可以分解成许多独立执行的线E,每个U程q行的运行在同一q程中? 一个进E中的所有线E都在该q程的虚拟地址I间中,使用该进E的全局变量和系l资源。操作系l给每个U程分配不同的CPU旉片,在某一个时刻,CPU只执行一个时间片内的U程Q多个时间片中的相应U程在CPU内轮执行,׃每个旉片时间很短,所以对用户来说Q仿佛各个线E在计算Z是ƈ行处理的。操作系l是ҎU程的优先来安排CPU的时_优先U高的线E优先运行,优先U低的线E则l箋{待? U程被分ZU:用户界面U程和工作线E(又称为后台线E)。用L面线E通常用来处理用户的输入ƈ响应各种事g和消息,其实Q应用程序的L行线ECWinAPP对象是一个用L面线E,当应用程序启动时自动创徏和启动,同样它的l止也意味着该程序的l束Q进城终止。工作者线E用来执行程序的后台处理dQ比如计、调度、对串口的读写操作等Q它和用L面线E的区别是它不用从CwinThreadcL生来创徏Q对它来说最重要的是如何实现工作U程d的运行控制函数。工作线E和用户界面U程启动时要调用同一个函数的不同版本Q最后需要读者明白的是,一个进E中的所有线E共享它们父q程的变量,但同时每个线E可以拥有自q变量? 二?U程的管理和操作 1Q?U程的启? 创徏一个用L面线E,首先要从cCwinThread产生一个派生类Q同时必M用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE来声明和实现q个CwinThreadzcR? W二步是Ҏ需要重载该zcȝ一些成员函数如QExitInstance()QInitInstance()QOnIdle();PreTranslateMessage(){函敎ͼ最后启动该用户界面U程Q调用AfxBeginThread()函数的一个版本:CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );其中W一个参Cؓ指向定义的用L面线E类指针变量Q第二个参数为线E的优先U,W三个参CؓU程所对应的堆栈大,W四个参CؓU程创徏时的附加标志Q缺省ؓ正常状态,如ؓCREATE_SUSPENDED则线E启动后为挂L态? 对于工作U程来说Q启动一个线E,首先需要编写一个希望与应用E序的其余部分ƈ行运行的函数如Fun1()Q接着定义一个指向CwinThread对象的指针变?pThread,调用AfxBeginThread(Fun1,param,priority)函数Q返回glpThread变量的同时一q启动该U程来执行上面的Fun1()函数Q其中Fun1是线E要q行的函数的名字Q也既是上面所说的控制函数的名字,param是准备传送给U程函数Fun1的Q?2位|priority则是定义该线E的优先U别Q它是预定义的常敎ͼ读者可参考MSDN? 2Q线E的优先U? 以下的CwinThreadcȝ成员函数用于U程优先U的操作Q? int GetThreadPriority(); BOOL SetThradPriority()(int nPriority); 上述的二个函数分别用来获取和讄U程的优先Q这里的优先U,是相对于该线E所处的优先权层ơ而言的,处于同一优先权层ơ的U程Q优先高的U程先运行;处于不同优先权层ơ上的线E,谁的优先权层ơ高Q谁先运行。至于优先讄所需的常敎ͼ自己参考MSDN可以了Q要注意的是要想讄U程的优先Q这个线E在创徏时必d有THREAD_SET_INFORMATION讉K权限。对于线E的优先权层ơ的讄QCwinThreadcL有提供相应的函数Q但是可以通过Win32 SDK函数GetPriorityClass()和SetPriorityClass()来实现? 3Q线E的悬挂、恢? CwinThreadcM包含了应用程序悬挂和恢复它所创徏的线E的函数Q其中SuspendThread()用来悬挂U程Q暂停线E的执行QResumeThread()用来恢复U程的执行。如果你对一个线E连l若q次执行SuspendThread()Q则需要连l执行相应次的ResumeThread()来恢复线E的q行? 4Q结束线E? l止U程有三U途径Q线E可以在自n内部调用AfxEndThread()来终止自w的q行Q可以在U程的外部调用BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode )来强行终止一个线E的q行Q然后调用CloseHandleQ)函数释放U程所占用的堆栈;W三U方法是改变全局变量QɾU程的执行函数返回,则该U程l止。下面以W三U方法ؓ例,l出部分代码Q? //////////////////////////////////////////////////////////////// //////CtestView message handlers /////Set to True to end thread Bool bend=FALSE;//定义的全局变量Q用于控制线E的q行 //The Thread Function UINT ThreadFunction(LPVOID pParam)//U程函数 { while(!bend) {Beep(100,100); Sleep(1000); } return 0; } CwinThread *pThread; HWND hWnd; ///////////////////////////////////////////////////////////// Void CtestView::OninitialUpdate() { hWnd=GetSafeHwnd(); pThread=AfxBeginThread(ThradFunction,hWnd);//启动U程 pThread->m_bAutoDelete=FALSE;//U程为手动删? Cview::OnInitialUpdate(); } //////////////////////////////////////////////////////////////// Void CtestView::OnDestroy() { bend=TRUE;//改变变量Q线E结? WaitForSingleObject(pThread->m_hThread,INFINITE);//{待U程l束 delete pThread;//删除U程 Cview::OnDestroy(); } 三?U程之间的通信 通常情况下,一个次U线E要ZU程完成某种特定cd的Q务,q就隐含着表示在主U程和次U线E之间需要徏立一个通信的通道。一般情况下Q有下面的几U方法实现这U通信dQ用全局变量Q上一节的例子其实使用的就是这U方法)、用事件对象、用消息。这里我们主要介l后两种Ҏ? 1Q?利用用户定义的消息通信 在WindowsE序设计中,应用E序的每一个线E都拥有自己的消息队列,甚至工作U程也不例外Q这样一来,׃得线E之间利用消息来传递信息就变的非常单。首先用戯定义一个用h息,如下所C:#define WM_USERMSG WMUSER+100Q在需要的时候,在一个线E中调用 Q:PostMessage((HWND)param,WM_USERMSG,0,0) ? CwinThread::PostThradMessage() 来向另外一个线E发送这个消息,上述函数的四个参数分别是消息要发送到的目的窗口的句柄、要发送的消息标志W、消息的参数WPARAM和LPARAM。下面的代码是对上节代码的修改,修改后的l果是在U程l束时显CZ个对话框Q提C线E结束: UINT ThreadFunction(LPVOID pParam) { while(!bend) { Beep(100,100); Sleep(1000); } Q:PostMessage(hWnd,WM_USERMSG,0,0)Q? return 0; } ////////WM_USERMSG消息的响应函CؓOnThreadended(WPARAM wParam,LPARAM lParam) LONG CTestView::OnThreadended(WPARAM wParam,LPARAM lParam) { AfxMessageBox("Thread ended."); Retrun 0; } 上面的例子是工作者线E向用户界面U程发送消息,对于工作者线E,如果它的设计模式也是消息驱动的,那么调用者可以向它发送初始化、退出、执行某U特定的处理{消息,让它在后台完成。在控制函数中可以直接用:QGetMessage()q个SDK函数q行消息分检和处理,自己实现一个消息@环。GetMessage()函数在判断该U程的消息队列ؓI时Q线E将pȝ分配l它的时间片让给其它U程Q不无效的占用CPU的时_如果消息队列不ؓI,p取这个消息,判断q个消息的内容ƈq行相应的处理? 2Q用事g对象实现通信 在线E之间传递信可行通信比较复杂的方法是使用事g对象Q用MFC的Ceventcȝ对象来表C。事件对象处于两U状态之一Q有信号和无信号Q线E可以监视处于有信号状态的事gQ以便在适当的时候执行对事g的操作。上qC子代码修改如下: //////////////////////////////////////////////////////////////////// Cevent threadStart,threadEnd; //////////////////////////////////////////////////////////////////// UINT ThreadFunction(LPVOID pParam) { Q:WaitForSingleObject(threadStart.m_hObject,INFINITE); AfxMessageBox("Thread start."); while(!bend) { Beep(100,100); Sleep(1000); Int result=::WaitforSingleObject(threadEnd.m_hObject,0); //{待threadEnd事g有信P无信hU程在这里悬? If(result==Wait_OBJECT_0) Bend=TRUE; } Q:PostMessage(hWnd,WM_USERMSG,0,0)Q? return 0; } ///////////////////////////////////////////////////////////// Void CtestView::OninitialUpdate() { hWnd=GetSafeHwnd(); threadStart.SetEvent();//threadStart事g有信? pThread=AfxBeginThread(ThreadFunction,hWnd);//启动U程 pThread->m_bAutoDelete=FALSE; Cview::OnInitialUpdate(); } //////////////////////////////////////////////////////////////// Void CtestView::OnDestroy() { threadEnd.SetEvent(); WaitForSingleObject(pThread->m_hThread,INFINITE); delete pThread; Cview::OnDestroy(); } q行q个E序Q当关闭E序Ӟ才显C提C框Q显C?Thread ended" 四?U程之间的同? 前面我们讲过Q各个线E可以访问进E中的公共变量,所以用多U程的过E中需要注意的问题是如何防止两个或两个以上的线E同时访问同一个数据,以免破坏数据的完整性。保证各个线E可以在一起适当的协调工作称为线E之间的同步。前面一节介l的事g对象实际上就是一U同步Ş式。Visual C++中用同步类来解x作系l的q行性而引L数据不安全的问题QMFC支持的七个多U程的同步类可以分成两大c:同步对象QCsyncObject、Csemaphore、Cmutex、CcriticalSection和CeventQ和同步讉K对象QCmultiLock和CsingleLockQ。本节主要介l界区Qcritical sectionQ、互斥(mutexeQ、信号量QsemaphoreQ,q些同步对象使各个线E协调工作,E序q行h更安全? 1Q?临界? 临界区是保证在某一个时间只有一个线E可以访问数据的Ҏ。用它的过E中Q需要给各个U程提供一个共享的临界区对象,无论哪个U程占有临界区对象,都可以访问受C护的数据Q这时候其它的U程需要等待,直到该线E释放界区对象为止Q界区被释攑Q另外的U程可以强占q个临界区,以便讉K׃n的数据。界区对应着一个CcriticalSection对象Q当U程需要访问保护数据时Q调用界区对象的Lock()成员函数Q当对保护数据的操作完成之后Q调用界区对象的Unlock()成员函数释放对界区对象的拥有权Q以使另一个线E可以夺取界区对象q访问受保护的数据。同时启动两个线E,它们对应的函数分别ؓWriteThread()和ReadThread()Q用以对公共数组larray[]操作Q下面的代码说明了如何用界区对象Q? #include "afxmt.h" int array[10],destarray[10]; CCriticalSection Section; //////////////////////////////////////////////////////////////////////// UINT WriteThread(LPVOID param) {Section.Lock(); for(int x=0;x<10;x++) array[x]=x; Section.Unlock(); } UINT ReadThread(LPVOID param) { Section.Lock(); For(int x=0;x<10;x++) Destarray[x]=array[x]; Section.Unlock(); } 上述代码q行的结果应该是Destarray数组中的元素分别?-9Q而不是杂乱无章的敎ͼ如果不用同步,则不是这个结果,有兴的读者可以实验一下? 2Q?互斥 互斥与界区很相|但是使用时相对复杂一些,它不仅可以在同一应用E序的线E间实现同步Q还可以在不同的q程间实现同步,从而实现资源的安全׃n。互斥与Cmutexcȝ对象相对应,使用互斥对象Ӟ必须创徏一个CSingleLock或CMultiLock对象Q用于实际的讉K控制Q因里的例子只处理单个互斥,所以我们可以用CSingleLock对象Q该对象的Lock()函数用于占有互斥QUnlock()用于释放互斥。实C码如下: #include "afxmt.h" int array[10],destarray[10]; CMutex Section; ///////////////////////////////////////////////////////////// UINT WriteThread(LPVOID param) { CsingleLock singlelock; singlelock (&Section); singlelock.Lock(); for(int x=0;x<10;x++) array[x]=x; singlelock.Unlock(); } UINT ReadThread(LPVOID param) { CsingleLock singlelock; singlelock (&Section); singlelock.Lock(); For(int x=0;x<10;x++) Destarray[x]=array[x]; singlelock.Unlock(); } 3Q?信号? 信号量的用法和互斥的用法很相|不同的是它可以同一时刻允许多个U程讉K同一个资源,创徏一个信号量需要用Csemaphorecd明一个对象,一旦创Z一个信号量对象Q就可以用它来对资源的访问技术。要实现计数处理Q先创徏一个CsingleLock或CmltiLock对象Q然后用该对象的Lock()函数减少q个信号量的计数|Unlock()反之。下面的代码分别启动三个U程Q执行时同时昄二个消息框,然后10U后W三个消息框才得以显C? ///////////////////////////////////////////////////////////////// Csemaphore *semaphore; Semaphore=new Csemaphore(2,2); HWND hWnd=GetSafeHwnd(); AfxBeginThread(threadProc1,hWnd); AfxBeginThread(threadProc2,hWnd); AfxBeginThread(threadProc3,hWnd); ////////////////////////////////////////////////////////////////////// UINT ThreadProc1(LPVOID param) {CsingleLock singelLock(semaphore); singleLock.Lock(); Sleep(10000); ::MessageBox((HWND)param,"Thread1 had access","Thread1",MB_OK); return 0; } UINT ThreadProc2(LPVOID param) {CSingleLock singelLock(semaphore); singleLock.Lock(); Sleep(10000); ::MessageBox((HWND)param,"Thread2 had access","Thread2",MB_OK); return 0; } UINT ThreadProc3(LPVOID param) {CsingleLock singelLock(semaphore); singleLock.Lock(); Sleep(10000); ::MessageBox((HWND)param,"Thread3 had access","Thread3",MB_OK); return 0; } 对复杂的应用E序来说Q线E的应用l应用程序提供了高效、快速、安全的数据处理能力。本文讲qCU程中经帔R到的问题Q希望对读者朋友有一定的帮助?/TD> |