CreateWaitableTimer和SetWaitableTimer函数(定时器)

用户感觉到软件的好用,就是可以定时地做一些工作,而不需要人参与进去。比如每天定时地升级病毒库,定时地下载电影,定时地更新游戏里的人物。要想实现这些功能,就可以使用定时器的API函数CreateWaitableTimer和SetWaitableTimer来实现了,这对API函数创建的时钟是比较精确的,可以达到100倍的10亿分之一秒。 函数CreateWaitableTimer和SetWaitableTimer声明如下: WINBASEAPI __out HANDLE WINAPI CreateWaitableTimerA( __in_opt LPSECURITY_ATTRIBUTES lpTimerAttributes, __in BOOL bManualReset, __in_opt LPCSTR lpTimerName ); WINBASEAPI __out HANDLE WINAPI CreateWaitableTimerW( __in_opt LPSECURITY_ATTRIBUTES lpTimerAttributes, __in BOOL bManualReset, __in_opt LPCWSTR lpTimerName ); #ifdef UNICODE #define CreateWaitableTimer CreateWaitableTimerW #else #define CreateWaitableTimer CreateWaitableTimerA #endif // !UNICODE WINBASEAPI BOOL WINAPI SetWaitableTimer( __in HANDLE hTimer, __in const LARGE_INTEGER *lpDueTime, __in LONG lPeriod, __in_opt PTIMERAPCROUTINE pfnCompletionRoutine, __in_opt LPVOID lpArgToCompletionRoutine, __in BOOL fResume ); lpTimerAttributes是设置定时器的属性。 bManualReset是是否手动复位。 lpTimerName是定时器的名称。 hTimer是定时器的句柄。 lpDueTime是设置定时器时间间隔,当设置为正值是绝对时间;当设置为负数是相对时间。 lPeriod是周期。 pfnCompletionRoutine是设置回调函数。 lpArgToCompletionRoutine是传送给回调函数的参数。 fResume是设置系统是否自动恢复。 调用函数的例子如下: #001 //创建定时器 #002 //蔡军生 2007/11/06 QQ:9073204 深圳 #003 int CreateTestTimer(void) #004 { #005 HANDLE hTimer = NULL; #006 LARGE_INTEGER liDueTime; #007 #008 //设置相对时间为10秒。 #009 liDueTime.QuadPart = -100000000; #010 #011 ; //创建定时器。 #012 hTimer = CreateWaitableTimer(NULL, TRUE, _T("TestWaitableTimer")); #013 if (!hTimer) #014 { #015 return 1; #016 } #017 #018 OutputDebugString(_T("10秒定时器/r/n")); #019 #020 // 设置10秒钟。 #021 if (!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0)) #022 { #023 // #024 CloseHandle(hTimer); #025 return 2; #026 } #027 #028 //等定时器有信号。 while(true) { #029 if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0) #030 { #031 OutputDebugString(_T("10秒定时器出错了/r/n")); #032 // #033 CloseHandle(hTimer); #034 return 3; #035 } #036 else #037 { #038 //10秒钟到达。 SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0);//将hTimer信息重置为无信号,如果不然就会不断的输出 #039 OutputDebugString(_T("10秒定时器到了/r/n")); //“10秒定时器到了”这一句 #040 } #041 } #042 // #043 CloseHandle(hTimer); #044 return 0; #045 } 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiangxinyu/archive/2008/07/23/2696447.aspx 通过异步程序调用(APC)实现的定时功能 编译:张海粟   定时器是一个在特定时间或者规则间隔被激发的内核对象。结合定时器的异步程序调用可以允许回调函数在任何定时器被激发的时候执行。本文的例子代码显示了如何实现。   使用本定时器时,你需要把常量_WIN32_WINNT定义为0x0400,并且此常量应该在包之前定义,以确保声明合适的定时器原型函数。   通过调用CreateWaitableTimer()可以创建一个定时器,此函数返回一个指向内核对象的句柄。若定时器已经存在,你可以通过使用 OpenWaitableTimer()获得一个进程相关的句柄。无论是通过CreateWaitableTimer() 还是通过OpenWaitableTimer()获得的句柄,在不需要定 时器时必须释放,方法是使用函数CloseHandle()。   定时的时间通过调用SetWaitableTimer()来设置,可以设置为一个特定的时刻(如December 16, 1999 at 9:45 PM)或者一个相对的时间(如从现在起每五分钟)。函数SetWaitableTime()定时的时间参数要求LARGE_INTEGER类型。这个值应该符合在结构体FILETIME中描述的格式。如果值是正的,代表一个特定的时刻。如果值是负的,代表以100纳秒为单位的相对时间。后面的示例代码中使用的是相对时间。在调用SetWaitableTimer()函数后,定时器将在每5秒被激发一次。   你也可以将定时器设置为周期性的自我激发,方法是向SetWaitableTimer()的第三个参数传递一个周期参数(以毫秒为单位)。在CreateWaitableTimer()的第二个参数传递FALSE可以产生一个自动归零的定时器。本例设置周期为两秒的定时器。   当设置了定时器之后,你就可以将APC与其结合起来。这里把APC函数称作完全例程。完全例程的地址作为SetWaitableTimer()的第四个参数。第五个参数是一个空类型的指针,你可以使用它来传递完全例程的参数。   在所有的APC中,要执行一个完全例程则线程必须处于监听状态。完全例程将总是被调用SetWaitableTimer()的相同的线程执行,所以此线程必须将必须其自身置于监听状态。可以调用下面的任何一个监听函数来完成监听状态的设置: •SleepEx(); •WaitForSingleObjectEx(); •WaitForMultipleObjectsEx(); •MsgWaitForMultipleObjectsEx(); •SignalObjectAndWait();   任何一个线程都有一个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 #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 ); } } 摘自:http://www.vckbase.com/document/viewdoc/?id=1587 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hkx1n/archive/2010/11/09/5997560.aspx
以下是贪吃蛇的C语言代码,使用了线程和定时器实现: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #include <windows.h> #define MAP_WIDTH 40 #define MAP_HEIGHT 20 #define SNAKE_INIT_LENGTH 3 #define SNAKE_MAX_LENGTH 100 // 定义方向 enum Direction { UP, DOWN, LEFT, RIGHT }; // 定义蛇的结构体 struct Snake { int x[SNAKE_MAX_LENGTH]; int y[SNAKE_MAX_LENGTH]; int length; enum Direction direction; }; // 定义食物的结构体 struct Food { int x; int y; }; // 定义地图 char map[MAP_HEIGHT][MAP_WIDTH]; // 定义蛇和食物 struct Snake snake; struct Food food; // 定义线程和定时器 HANDLE hTimer; HANDLE hThread; // 初始化地图 void init_map() { int i, j; for (i = 0; i < MAP_HEIGHT; i++) { for (j = 0; j < MAP_WIDTH; j++) { if (i == 0 || i == MAP_HEIGHT - 1 || j == 0 || j == MAP_WIDTH - 1) map[i][j] = '#'; else map[i][j] = ' '; } } } // 初始化蛇 void init_snake() { int i; snake.length = SNAKE_INIT_LENGTH; snake.direction = RIGHT; for (i = 0; i < SNAKE_INIT_LENGTH; i++) { snake.x[i] = MAP_WIDTH / 2 - i; snake.y[i] = MAP_HEIGHT / 2; } } // 初始化食物 void init_food() { srand(time(NULL)); food.x = rand() % (MAP_WIDTH - 2) + 1; food.y = rand() % (MAP_HEIGHT - 2) + 1; } // 更新地图 void update_map() { int i, j; for (i = 0; i < MAP_HEIGHT; i++) { for (j = 0; j < MAP_WIDTH; j++) { if (i == 0 || i == MAP_HEIGHT - 1 || j == 0 || j == MAP_WIDTH - 1) map[i][j] = '#'; else map[i][j] = ' '; } } for (i = 0; i < snake.length; i++) { map[snake.y[i]][snake.x[i]] = '*'; } map[food.y][food.x] = '@'; } // 控制蛇的移动 void move_snake() { int i; for (i = snake.length - 1; i > 0; i--) { snake.x[i] = snake.x[i - 1]; snake.y[i] = snake.y[i - 1]; } switch (snake.direction) { case UP: snake.y[0]--; break; case DOWN: snake.y[0]++; break; case LEFT: snake.x[0]--; break; case RIGHT: snake.x[0]++; break; } } // 判断蛇是否吃到食物 void eat_food() { if (snake.x[0] == food.x && snake.y[0] == food.y) { snake.length++; if (snake.length > SNAKE_MAX_LENGTH) snake.length = SNAKE_MAX_LENGTH; init_food(); } } // 判断蛇是否撞墙或者撞到自己 int is_dead() { int i; if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH - 1 || snake.y[0] == 0 || snake.y[0] == MAP_HEIGHT - 1) return 1; for (i = 1; i < snake.length; i++) { if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) return 1; } return 0; } // 游戏结束 void gameover() { printf("Game Over!\n"); printf("Press any key to continue...\n"); _getch(); exit(0); } // 控制蛇的方向 void control() { if (_kbhit()) { switch (_getch()) { case 'w': if (snake.direction != DOWN) snake.direction = UP; break; case 's': if (snake.direction != UP) snake.direction = DOWN; break; case 'a': if (snake.direction != RIGHT) snake.direction = LEFT; break; case 'd': if (snake.direction != LEFT) snake.direction = RIGHT; break; } } } // 定时器回调函数 VOID CALLBACK timer_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) { move_snake(); eat_food(); update_map(); control(); if (is_dead()) gameover(); } // 线程函数 DWORD WINAPI thread_func(LPVOID lpParam) { while (1) { WaitForSingleObject(hTimer, INFINITE); } return 0; } // 主函数 int main() { init_map(); init_snake(); init_food(); update_map(); printf("Press any key to start...\n"); _getch(); hTimer = CreateWaitableTimer(NULL, FALSE, NULL); LARGE_INTEGER liDueTime; liDueTime.QuadPart = 0; SetWaitableTimer(hTimer, &liDueTime, 1000 / 10, timer_callback, NULL, FALSE); hThread = CreateThread(NULL, 0, thread_func, NULL, 0, NULL); while (1) { system("cls"); int i, j; for (i = 0; i < MAP_HEIGHT; i++) { for (j = 0; j < MAP_WIDTH; j++) { printf("%c", map[i][j]); } printf("\n"); } Sleep(1000 / 10); } return 0; } ``` 上面的代码中,使用了定时器和线程来控制蛇的移动和游戏的进行。其中,定时器用来定时调用回调函数,线程用来等待定时器的信号。回调函数中包含了蛇的移动、吃食物、更新地图、控制方向等逻辑,线程函数中输出地图并等待定时器的信号。通过这种方式,可以实现一个简单的贪吃蛇游戏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值