毫秒級定時器

1.       windows平臺用微軟提供的多媒體定時器。

2.       linux平臺用select方案。

 

  多媒體定時器方案

   Visual C++中提供了很多關於時間操作的函數,利用它們控制程序能夠精確地完成定時和計時操作。Visaul C++中的WM_TIMER消息映射能進行簡單的時間控制。首先調用函數SetTimer()設置定時間隔(退出程序時別忘了調用和SetTimer()配對使用的KillTimer()函數),如SetTimer(0,200,NULL)即爲設置200ms的時間間隔。然後在應用程序中增加定時響應函數OnTimer(),並在該函數中添加響應的處理語句,用來完成到達定時時間的操作。這種定時方法非常簡單,但其定時功能如同Sleep()函數的延時功能一樣,精度非常低,只可以用來實現諸如位圖的動態顯示等對定時精度要求不高的情況。

  微軟公司在其多媒體Windows中提供了精確定時器的底層API支持。利用多媒體定時器可以很精確地讀出系統的當前時間,並且能在非常精確的時間間隔內完成一個事件、函數或過程的調用。利用多媒體定時器的基本功能,可以通過兩種方法實現精確定時。1)使用timeGetTime()函數,該函數定時精度爲ms級,返回從Windows啓動開始所經過的時間。由於使用該函數是通過查詢的方式進行定時控制的,所以,應該建立定時循環來進行定時事件的控制。2)使用timeSetEvent()函數,該函數原型如下:

 

 

MMRESULT timeSetEvent(UINT uDelayUINT uResolutionLPTIMECALLBACK lpTimeProcDWORD dwUserUINT fuEvent)

 

 

該函數的參數說明如下:參數uDelay表示延遲時間;參數uResolution表示時間精度,在Windows中缺省值爲1mslpTimeProc表示回調函數,爲用戶自定義函數,定時調用; 參數dwUser表示用戶提供的回調數據;參數fuEvent爲定時器的事件類型,TIME_ONESHOT表示執行一次;TIME_PERIODIC:週期性執行。具體應用時,可以通過調用timeSetEvent()函數,將需要週期性執行的任務定義在lpTimeProc回調函數中(如:定時採樣、控制等),從而完成所需處理的事件。需要注意的是:任務處理的時間不能大於週期間隔時間。另外,在定時器使用完畢後,應及時調用timeKillEvent()將之釋放。

 

 

#ifdef WIN32

    if (NULL != g_TimerID)

    {

        MMRESULT ret;

        ret = timeKillEvent(g_TimerID);

        if (TIMERR_NOERROR != ret)

        {           

            g_debug("timeKillEvent failed.");

        }

        else

        {

            g_TimerID = NULL;    

        }

    } 

   

    {

        g_TimerID = timeSetEvent(40, 1,    //40毫秒

            (LPTIMECALLBACK) DoProcess,

            (DWORD)this,TIME_PERIODIC);

       

        if (NULL == g_TimerID)

        {

            g_debug("create mm timer failed.");

        }

    }   

#endif

 

 

 

select方案:  

 

struct timeval tv;

    struct sched_param task_param;   

    //提高優先級

    task_param.sched_priority = 80;

   

    if( pthread_setschedparam(pthread_self(), SCHED_FIFO, &task_param) )

    {

        g_debug("set task priority failed: %s/n", strerror(errno));

    }

 

    BOOL32 bActive = TRUE;

   

    while(bActive)

    {       

      

        bActive = GetActiveStatus();

 

        //定時器

        for (l32 i = 0; i < 40; i++)  //40毫秒

        {

            tv.tv_sec = 0;  

            tv.tv_usec = 1000;          

            select(0, NULL, NULL, NULL, &tv); 

        }       

           

        g_mutex_lock((GMutex*)(ptLock));

        g_cond_signal((GCond*)(ptCond));

        g_mutex_unlock((GMutex*)(ptLock));                

    }

 

 

 

Select方案關鍵點:  

1)      select作定時器要單獨起線程並且提高線程優先級。

2)      線程中除了給信號不做其它任何有負載的工作。

3)      Select語句要用循環實現。

 

 

內核信息:

Linux localhost.localdomain 2.6.18-8.el5 #1 SMP Thu Mar 15 19:57:35 EDT 2007 i68

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章