日期:2014-05-16 浏览次数:21007 次
多线程编程经常遇到以下问题:主线程退出前,后台线程也优雅的退出。如果后台线程处于阻塞状态,则需要把阻塞线程激活。本文讨论Windows下面,三种激活阻塞线程的方法。
第一种:利用WaitForMultipleObjects函数让线程处于阻塞状态,并设置多个等待对象中的任一对象处于signal状态下都返回。此时向WaitForMultipleObjects传递的等待对象数组要包含一个额外的通知对象,主线程通过signal该通知对象,来激活阻塞线程。
第三种:利用SleepEx,SignalObjectAndWait,WaitForSingleObjectEx,WaitForMultipleObjectsEx,或MsgWaitForMultipleObjectsEx函数使得线程处于alertable阻塞状态。此时主线程通过QueueUserAPC函数向阻塞线程发送一个APC对象,使得阻塞线程从阻塞中返回。
以下代码用MsgWaitForMultipleObjectsEx函数演示了这三种方法。
#include "stdafx.h" #include <Windows.h> #include <process.h> #include <stdio.h> HANDLE hStartEvent; // thread start event HANDLE hStopEvent; // thread stop event unsigned _stdcall ThreadProc(PVOID param) { // 创建消息循环,并通知主线程消息循环创建成功 MSG tmpMsg; PeekMessage(&tmpMsg, NULL, WM_USER, WM_USER, PM_NOREMOVE); if (!SetEvent(hStartEvent)) //set thread start event return 1; HANDLE arEvents[1] = { hStopEvent } ; while (TRUE) { MSG msg ; while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { if (msg.message == WM_QUIT) { // quit msg printf("quit msg received\n"); return 0 ; } DispatchMessage(&msg); } DWORD result ; result = MsgWaitForMultipleObjectsEx( 1 , arEvents , INFINITE, QS_ALLINPUT, MWMO_ALERTABLE ); if (result == WAIT_OBJECT_0 + 1) // msg received { continue; } else if(result == WAIT_OBJECT_0){ // stop event printf("stop event signaled\n"); return 0; } else if(result == WAIT_IO_COMPLETION ){ // apc printf("iocp received\n"); return 0; } } } void _stdcall APCProc(ULONG_PTR dwParam) { // nothing to do } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hThread; unsigned nThreadID; hStartEvent = ::CreateEvent(0,FALSE,FALSE,0); hStopEvent = ::CreateEvent(0, FALSE, FALSE, 0); if(hStartEvent == 0) { printf("create start event failed,errno:%d\n",GetLastError()); return 1; } //start thread hThread = (HANDLE)_beginthreadex( NULL, 0, &ThreadProc, NULL, 0, &nThreadID ); if(hThread == 0) { printf("start thread failed,errno:%d\n",GetLastError()); CloseHandle(hStartEvent); return 1; } // 等待线程启动消息循环 ::WaitForSingleObject(hStartEvent,INFINITE); CloseHandle(hStartEvent); #ifdef METHOD_EVENT // 第一种方法,激活线程正在等待的事件 ::SetEvent(hStopEvent); #else #ifdef METHOD_MSG // 第二种方法,向线程发送消息 if( !PostThreadMessage(nThreadID, WM_QUIT, 0, 0)) { printf("post message failed,errno:%d\n",GetLastError()); } #else #ifdef METHOD_APC // 第三种方法,向线程推送一个UserAPC if(QueueUserAPC(APCProc, hThread, 0) == 0){ printf("QueueUserAPC failed,errno:%d\n",GetLastError()); } #else #pragma message("Error: define METHOD_EVENT or METHOD_MSG or METHOD_APC") #endif #endif #endif // 等待线程退出 if(WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) { printf("WaitForSingleObject failed,errno:%d\n",GetLastError()); } CloseHandle(hThread); return 1; }