邢红瑞的blog--如何在控制台程序中使用定时器

导读:
  这是一个看似简单,但是很复杂的问题,因为windows使用WM_TIMER,但是console下没有Hwnd,没有消息分发器,不象unix下可以用alarm信号定时执行某个函数,不知道java是如何实现的。
  想起masterz曾经给出过例子,自从做java后,再也没有见过他。其实这个也不难,但首先要保证你的定时器要在一个线程中设置,如果你用MFC,那么在控制台中你可以从CWinThread派生一个类,然后在这个类中设置定时器,但不像CWnd类中的定时器那么好用。
  user timer in workthread of console app
  #include
  #include
  #include
  unsigned long WINAPI Thread(PVOID pvoid);
  void main()
  {
  DWORD dwThreadId;
  printf("use timer in workthread of console application/n");
  HANDLE hThread = CreateThread(
  NULL, // no security attributes
  0, // use default stack size
  Thread, // thread function
  0, // argument to thread function
  0, // use default creation flags
  &dwThreadId);
  DWORD dwwait=WaitForSingleObject(hThread,1000*30);
  switch(dwwait)
  {
  case WAIT_ABANDONED:
  printf("main thread WaitForSingleObject return WAIT_ABANDONED/n");
  break;
  case WAIT_OBJECT_0:
  printf("main thread WaitForSingleObject return WAIT_OBJECT_0/n");
  break;
  case WAIT_TIMEOUT:
  printf("main thread WaitForSingleObject return WAIT_TIMEOUT/n");
  break;
  }
  CloseHandle(hThread);
  _getch();
  }
  
  unsigned long WINAPI Thread(PVOID pvoid)
  {
  MSG msg;
  PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
  UINT timerid=SetTimer(NULL,111,3000,NULL);
  BOOL bRet;
  int count =0;
  while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
  {
  if (bRet == -1)
  {
  // handle the error and possibly exit
  }
  else
  if(msg.message==WM_TIMER)
  {
  count++;
  printf("WM_TIMER in work thread count=%d/n",count);
  if(count>4)
  break;
  }
  else
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
  }
  KillTimer(NULL,timerid);
  printf("thread end here/n");
  return 0;
  }
  另一个例子
  #include
  class foo_class {
  static int counter;
  public:
  static void __stdcall timer_proc(HWND,unsigned int, unsigned int, unsigned long) {
  if (counter++ <20)
  MessageBox(0,"Hello","MessageBox",0);
  else
  PostQuitMessage(0);
  }
  };
  int foo_class::counter=0;
  WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) {
  int iTimerID = SetTimer(0, 0, 300, foo_class::timer_proc);
  MSG m;
  while (GetMessage(&m,0,0,0)) {
  TranslateMessage(&m);
  DispatchMessage(&m);
  }
  return 1;
  }
  在win2k以后的平台使用CreateTimerQueue和CreateTimerQueueTimer
  msdn的例子
  // testTimer.cpp : Defines the entry point for the console application.
  //
  #include "stdafx.h"
  #define _WIN32_WINNT 0x0500
  #include   #include
  HANDLE gDoneEvent;
  VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
  {
  if (lpParam == NULL)
  {
  printf("TimerRoutine lpParam is NULL/n");
  }
  else
  {
  // lpParam points to the argument; in this case it is an int
  printf("Timer routine called. Parameter is %d./n",
  *(int*)lpParam);
  }
  //SetEvent(gDoneEvent);
  }
  int main()
  {
  HANDLE hTimer = NULL;
  HANDLE hTimerQueue = NULL;
  int arg = 123;
  // Use an event object to track the TimerRoutine execution
  gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  if (NULL == gDoneEvent)
  {
  printf("CreateEvent failed (%d)/n", GetLastError());
  return 1;
  }
  // Create the timer queue.
  hTimerQueue = CreateTimerQueue();
  if (NULL == hTimerQueue)
  {
  printf("CreateTimerQueue failed (%d)/n", GetLastError());
  return 2;
  }
  // Set a timer to call the timer routine in 10 seconds.
  if (!CreateTimerQueueTimer( &hTimer, hTimerQueue,
  (WAITORTIMERCALLBACK)TimerRoutine, &arg , 0, 1000*60, 0))
  {
  printf("CreateTimerQueueTimer failed (%d)/n", GetLastError());
  return 3;
  }
  // TODO: Do other useful work here
  printf("Call timer routine in 10 seconds.../n");
  // Wait for the timer-queue thread to complete using an event
  // object. The thread will signal the event at that time.
  if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
  printf("WaitForSingleObject failed (%d)/n", GetLastError());
  // Delete all timers in the timer queue.
  if (!DeleteTimerQueue(hTimerQueue))
  printf("DeleteTimerQueue failed (%d)/n", GetLastError());
  return 0;
  }
  如果编译不通过,只好动态加载CreateTimerQueue和CreateTimerQueueTimer
  typedef BOOL (WINAPI *CreateTimerQueueTimerT)( PHANDLE phNewTimer , HANDLE TimerQueue , WAITORTIMERCALLBACKFUNC Callback , PVOID Parameter , DWORD DueTime , DWORD Period , ULONG Flags );
  typedef HANDLE (*CreateTimerQueueT)(VOID);
  HMODULE hMod = LoadLibrary("kernel32.dll");
  if(hMod!=NULL)
  {
  CreateTimerQueueTimerT CreateTimerQueueTimer = (CreateTimerQueueTimerT)::GetProcAddress(hMod, "CreateTimerQueueTimer");
  CreateTimerQueueT CreateTimerQueue = (CreateTimerQueueT)::GetProcAddress(hMod, "CreateTimerQueue");
  if(CreateTimerQueueTimer!=NULL&&CreateTimerQueue!=NULL)
  {
  hTimerQueue = CreateTimerQueue();
  if (NULL == hTimerQueue)
  {
  printf("CreateTimerQueue failed (%d)/n", GetLastError());
  }
  
  const int ntimedelay=1000*60*3;
  if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, TimerRoutine, 0 , ntimedelay, ntimedelay, 0))
  {
  printf("CreateTimerQueueTimer failed (%d)/n", GetLastError());
  
  }
  }
  FreeLibrary(hMod);
  使用CreateWaitableTimer不需要麻烦,此时注意一般console建立的时候,是单线程,要改为多线程。
  #include "stdafx.h"
  #define _WIN32_WINNT 0x0400
  #include
  #include
  #include /* _beginthread, _endthread */
  #include
  #include
  #include
  unsigned __stdcall TF(void* arg) {
  HANDLE timer=(HANDLE) arg;
  while (1) {
  WaitForSingleObject(timer,INFINITE);
  printf(".");
  }
  }
  int main(int argc, char* argv[]) {
  HANDLE timer = CreateWaitableTimer(
  0,
  false, // false=>will be automatically reset
  0); // name
  LARGE_INTEGER li;
  const int unitsPerSecond=10*1000*1000; // 100 nano seconds
  // Set the event the first time 2 seconds
  // after calling SetWaitableTimer
  li.QuadPart=-(2*unitsPerSecond);
  SetWaitableTimer(
  timer,
  &li,
  750, // Set the event every 750 milli Seconds
  0,
  0,
  false);
  _beginthreadex(0,0,TF,(void*) timer,0,0);
  // Wait forever,
  while (1) ;
  return 0;
  }
  如果是XP ,使用多媒体定时器timeSetEvent()函数,该函数定时精度为ms级。利用该函数可以实现周期性的函数调用。函数的原型如下:
  MMRESULT timeSetEvent( UINT uDelay,
  UINT uResolution,
  LPTIMECALLBACK lpTimeProc,
  WORD dwUser,
  UINT fuEvent )
  该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数, 成功后返回事件的标识符代码,否则返回NULL。函数的参数说明如下:
  uDelay:以毫秒指定事件的周期。
  Uresolution:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。
  LpTimeProc:指向一个回调函数。
  DwUser:存放用户提供的回调数据。
  FuEvent:指定定时器事件类型:
  TIME_ONESHOT:uDelay毫秒后只产生一次事件
  TIME_PERIODIC :每隔uDelay毫秒周期性地产生事件。
  具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在LpTimeProc回调函数 中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是,任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后, 应及时调用timeKillEvent()将之释放。
  #include "stdafx.h"
  #include
  #include
  #include
  #pragma comment(lib,"Winmm.lib")
  void CALLBACK sig_forwin(long hwnd ,int uMsg , int dwUser ,long dw1 , long dw2)
  {
  printf("/nOK/n");
  }
  int main()
  {
  long ret ;
  
  ret = timeSetEvent(1000,1,( LPTIMECALLBACK )sig_forwin,0,TIME_PERIODIC);
  printf("ret = %d/n",ret);
  getchar();
  
  return 0 ;
  }

本文转自
http://www.w3china.org/blog/more.asp?name=hongrui&id=29543

你可能感兴趣的:(邢红瑞的blog--如何在控制台程序中使用定时器)