分类: C/C++
2008-08-04 09:35:53
任何一个线程都有一个APC队列。在调用上面的任何一个函数时,如果线程的APC队列中有实体,则此线程不会进入休眠状态,取而代之要做的是将实体从APC队列中取出,然后调用相应的完全例程。
如果在APC队列中不存在实体,那么线程将会被挂起,直至等待条件满足为止。满足等待条件的有:一个实体加入到APC队列中,超时,激活句柄等,以及在调用MsgWaitForMultipleObjectsEx()情况下,一个消息进入到线程的一个消息队列中。若等待条件满足的是APC队列中的一个实体,那么线程会被激活,并且执行完全例程,这种情况下的函数的返回值是 WAIT_IO_COMPLETION.
【重要提示】
1、在执行完一个完全例程之后,系统会检查在APC中剩下的实体以处理。一个监视函数仅仅在处理完所有APC实体后才返回。因此,如果实体加入到APC队列的速度比处理的更快的话,则调用这些函数可能永远也不能返回。特别当定时等待的时间比起要求执行完全例程的时间更短的话,这种情况更容易发生。
2、当使用APC来实现定时器时,设置定时的线程不应该等待定时器的句柄。如果等待定时器的句柄的话,则唤起这个线程的原因是定时器被激活,而不是有实体加入到APC队列中。这时线程将不再处于监听状态,所以完全例程也不会被调用。在本例中,Sleep()被用于将线程置于监听状态。在定时器激活后,如果有实体被加入到此线程的APC队列中时,Sleep()就会唤醒此线程。
【示例代码】
#define _WIN32_WINNT 0x0500 #include原文参考:Using a Waitable Timer with an Asynchronous Procedure Call 下载本文示例代码#include #define _SECOND 10000000 typedef struct _MYDATA { TCHAR *szText; DWORD dwValue; } MYDATA; VOID CALLBACK TimerAPCProc( LPVOID lpArg, // Data value DWORD dwTimerLowValue, // Timer low value DWORD dwTimerHighValue ) // Timer high value { MYDATA *pMyData = (MYDATA *)lpArg; printf( "Message: %s\nValue: %d\n\n", pMyData->szText, pMyData->dwValue ); MessageBeep(0); } void main( void ) { HANDLE hTimer; BOOL bSuccess; __int64 qwDueTime; LARGE_INTEGER liDueTime; MYDATA MyData; TCHAR szError[255]; MyData.szText = "This is my data."; MyData.dwValue = 100; if ( hTimer = CreateWaitableTimer( NULL, // Default security attributes FALSE, // Create auto-reset timer "MyTimer" ) ) // Name of waitable timer { __try { // Create an integer that will be used to signal the timer // 5 seconds from now. qwDueTime = -5 * _SECOND; // Copy the relative time into a LARGE_INTEGER. liDueTime.LowPart = (DWORD) ( qwDueTime & 0xFFFFFFFF ); liDueTime.HighPart = (LONG) ( qwDueTime >> 32 ); bSuccess = SetWaitableTimer( hTimer, // Handle to the timer object &liDueTime, // When timer will become signaled 2000, // Periodic timer interval of 2 seconds TimerAPCProc, // Completion routine &MyData, // Argument to the completion routine FALSE ); // Do not restore a suspended system if ( bSuccess ) { for ( ; MyData.dwValue < 1000; MyData.dwValue = 100 ) { SleepEx( INFINITE, // Wait forever TRUE ); // Put thread in an alertable state } } else { wsprintf( szError, "SetWaitableTimer failed with Error \ %d.", GetLastError() ); MessageBox( NULL, szError, "Error", MB_ICONEXCLAMATION ); } } __finally { CloseHandle( hTimer ); } } else { wsprintf( szError, "CreateWaitableTimer failed with Error %d.", GetLastError() ); MessageBox( NULL, szError, "Error", MB_ICONEXCLAMATION ); } }