内核式线程同步之waitable timer

waitable timer
      
顾名思义,就是隔一段时间被signaled的一种内核对象。waitable timer跟event对象一样可以在创建的时候指定reset方式,如果是manual-reset,那么当waitable timer对象被signaled时,所有等待这个对象的wait函数都会返回。如果是auto-reset那么就只有一个wait函数会返回。

创建完waitable timer对象后,必须通过SetWaitableTimer函数对它进行时间上的设置。时间格式是个问题,看下面代码

内核式线程同步之waitable timer// Declare our local variables.
内核式线程同步之waitable timer
HANDLE hTimer;
内核式线程同步之waitable timerSYSTEMTIME st;
内核式线程同步之waitable timerFILETIME ftLocal, ftUTC;
内核式线程同步之waitable timerLARGE_INTEGER liUTC;
内核式线程同步之waitable timer
内核式线程同步之waitable timer// Create an auto-reset timer.
内核式线程同步之waitable timer
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
内核式线程同步之waitable timer
内核式线程同步之waitable timer// First signaling is at January 1, 2002, at 1:00 P.M. (local time).
内核式线程同步之waitable timer
st.wYear         = 2002; // Year
内核式线程同步之waitable timer
st.wMonth        = 1;    // January
内核式线程同步之waitable timer
st.wDayOfWeek    = 0;    // Ignored
内核式线程同步之waitable timer
st.wDay          = 1;    // The first of the month
内核式线程同步之waitable timer
st.wHour         = 13;   // 1PM
内核式线程同步之waitable timer
st.wMinute       = 0;    // 0 minutes into the hour
内核式线程同步之waitable timer
st.wSecond       = 0;    // 0 seconds into the minute
内核式线程同步之waitable timer
st.wMilliseconds = 0;    // 0 milliseconds into the second
内核式线程同步之waitable timer

内核式线程同步之waitable timerSystemTimeToFileTime(&st, &ftLocal);
内核式线程同步之waitable timer
内核式线程同步之waitable timer// Convert local time to UTC time.
内核式线程同步之waitable timer
LocalFileTimeToFileTime(&ftLocal, &ftUTC);
内核式线程同步之waitable timer// Convert FILETIME to LARGE_INTEGER because of different alignment.
内核式线程同步之waitable timer
liUTC.LowPart  = ftUTC.dwLowDateTime;
内核式线程同步之waitable timerliUTC.HighPart = ftUTC.dwHighDateTime;
内核式线程同步之waitable timer
内核式线程同步之waitable timer// Set the timer.
内核式线程同步之waitable timer
SetWaitableTimer(hTimer, &liUTC, 6 * 60 * 60 * 1000, NULL, NULL, FALSE);

 

上面的代码查下MSDN应该很容易理解,这里要说的是CPU对齐的问题。FILETIME结构必须位于32位边界,而LARGE_INTEGER必须位于64位边界,所以不能将FILETIME直接传给SetWaitableTimer。

SetWaitableTimer也可以使用时间的绝对值,或者使用相对时间值。不过这时的值必须是负的。看下面代码:

内核式线程同步之waitable timer// Declare our local variables.
内核式线程同步之waitable timer
HANDLE hTimer;
内核式线程同步之waitable timerLARGE_INTEGER li;
内核式线程同步之waitable timer
内核式线程同步之waitable timer// Create an auto-reset timer.
内核式线程同步之waitable timer
hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
内核式线程同步之waitable timer
内核式线程同步之waitable timer// Set the timer to go off 5 seconds after calling SetWaitableTimer.
内核式线程同步之waitable timer
// Timer unit is 100-nanoseconds.
内核式线程同步之waitable timer
const int nTimerUnitsPerSecond = 10000000;
内核式线程同步之waitable timer
内核式线程同步之waitable timer// Negate the time so that SetWaitableTimer knows we 
内核式线程同步之waitable timer
// want relative time instead of absolute time.
内核式线程同步之waitable timer
// This indicate that the timer will be signaled 5 seconds after the call to SetWaitableTimer
内核式线程同步之waitable timer
li.QuadPart = -(5 * nTimerUnitsPerSecond); 
内核式线程同步之waitable timer 
内核式线程同步之waitable timer// Set the timer.
内核式线程同步之waitable timer
SetWaitableTimer(hTimer, &li, 6 * 60 * 60 * 1000, NULL, NULL, FALSE);

清除waitable timer对象需要用到CancelWaitableTimer函数。

特别提出的是waitable timer这节引出了一个新概念:APC(asynchronous procedure call)。按照我的理解,APC应该是线程特有的一个队列,里面装的是函数地址。如果一个函数地址被装入APC,如果这时线程处于待命的等待状态(alertable wait),那么这个线程就会被唤醒去调用APC里的函数;否则,APC里的函数地址就会被忽略掉。这里的这个线程指的是调用SetWaitableTimer的线程。下面的代码能说明问题

内核式线程同步之waitable timerVOID APIENTRY TimerAPCRoutine(PVOID pvArgToCompletionRoutine,
内核式线程同步之waitable timer   DWORD dwTimerLowValue, DWORD dwTimerHighValue) {
内核式线程同步之waitable timer
内核式线程同步之waitable timer   FILETIME ftUTC, ftLocal;
内核式线程同步之waitable timer   SYSTEMTIME st;
内核式线程同步之waitable timer   TCHAR szBuf[256];
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Put the time in a FILETIME structure.
内核式线程同步之waitable timer
   ftUTC.dwLowDateTime = dwTimerLowValue;
内核式线程同步之waitable timer   ftUTC.dwHighDateTime = dwTimerHighValue;
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Convert the UTC time to the user's local time.
内核式线程同步之waitable timer
   FileTimeToLocalFileTime(&ftUTC, &ftLocal);
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Convert the FILETIME to the SYSTEMTIME structure
内核式线程同步之waitable timer   
// required by GetDateFormat and GetTimeFormat.
内核式线程同步之waitable timer
   FileTimeToSystemTime(&ftLocal, &st);
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Construct a string with the 
内核式线程同步之waitable timer   
// date/time that the timer went off.
内核式线程同步之waitable timer
   GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, 
内核式线程同步之waitable timer      &st, NULL, szBuf, sizeof(szBuf) / sizeof(TCHAR));
内核式线程同步之waitable timer   _tcscat(szBuf, _ _TEXT(" "));
内核式线程同步之waitable timer   GetTimeFormat(LOCALE_USER_DEFAULT, 0,
内核式线程同步之waitable timer      &st, NULL, _tcschr(szBuf, 0), 
内核式线程同步之waitable timer      sizeof(szBuf) / sizeof(TCHAR) - _tcslen(szBuf));
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Show the time to the user.
内核式线程同步之waitable timer
   MessageBox(NULL, szBuf, "Timer went off at内核式线程同步之waitable timer", MB_OK);
内核式线程同步之waitable timer}

内核式线程同步之waitable timer
内核式线程同步之waitable timervoid SomeFunc() {
内核式线程同步之waitable timer   // Create a timer. (It doesn't matter whether it's manual-reset 
内核式线程同步之waitable timer   
// or auto-reset.)
内核式线程同步之waitable timer
   HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Set timer to go off in 5 seconds.
内核式线程同步之waitable timer
   LARGE_INTEGER li = { 0 };
内核式线程同步之waitable timer   SetWaitableTimer(hTimer, &li, 5000, TimerAPCRoutine, NULL, FALSE);
内核式线程同步之waitable timer
内核式线程同步之waitable timer   // Wait in an alertable state for the timer to go off.
内核式线程同步之waitable timer
   SleepEx(INFINITE, TRUE);
内核式线程同步之waitable timer
内核式线程同步之waitable timer   CloseHandle(hTimer);
内核式线程同步之waitable timer}

如果指定了APC,那么就不要等待这个waitable timer对象了,因为APC队列会唤醒线程的,不需要wait函数。

上一篇:菜鸟站长应该如何防止网站被恶意攻击


下一篇:jeecg前后端安装文档