1. 程式人生 > >linux定時器的實現方法

linux定時器的實現方法

this 就是 沒有 讀取數據 entry arm sigalrm read time

Linux提供定時器機制,可以指定在未來的某個時刻發生某個事件,定時器的結構如下:
struct timer_list 
{
    struct list_head list;
    unsigned long expires;
    unsigned long data;
    void (*function)(unsigned long);
};

list 實現的時候使用的,和定時器功能無關
expires 是定時器定時的滴答數(當前的滴答數為 jiffies )
function 到那個時刻內核調用的函數
data 由於可能多個定時器調用一個函數,為了使得這個函數能夠區分不同的定時器,
通過在結構中 data 來標識這個定時器,並且通過調用

function( data )

使得 function 能區分它們,也就是 data 起到 ID 的作用。

如何使用

將定時器加到定時器隊列中

void add_timer(struct timer_list *timer)

修改定時器的到期時間

int mod_timer(struct timer_list *timer, unsigned long expires)

將定時器刪除(以後這個定時器將不再起作用)

int del_timer(struct timer_list * timer)
如果不要求很精確的話,用 alarm() 和 signal() 就夠了 代碼:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void sigalrm_fn(int sig)
{
	printf("alarm!\n");
	alarm(2);
	return;
}
int main(void)
{
	signal(SIGALRM,signalrm_fn);
	alarm(2);
	while(1)
	pause();
}
用select()函數可以實現定時,而且可以將時間精確到毫秒級
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
int count = 0;
void set_timer()
{
        struct itimerval itv, oldtv;
        itv.it_interval.tv_sec = 5;
        itv.it_interval.tv_usec = 0;
        itv.it_value.tv_sec = 5;
        itv.it_value.tv_usec = 0;
 

        setitimer(ITIMER_REAL, &itv, &oldtv);
}

void sigalrm_handler(int sig)
{
        count++;
        printf("timer signal.. %d\n", count);
}

int main()
{
        signal(SIGALRM, sigalrm_handler);
        set_timer();
        while (count < 1000)
        {}
        exit(0);
}
利用定時器機制實現多線程編程

為了避免Qt系統中多線程編程帶來的問題,還可以使用系統中提供的定時器機制來實現類似的功能。定時器機制將並發的事件串行化,簡化了對並發事件的處理,從而避免了thread-safe方面問題的出現。 在下面的例子中,同時有若幹個對象需要接收底層發來的消息(可以通過Socket、FIFO等進程間通信機制),而消息是隨機收到的,需要有一個GUI主線程專門負責接收消息。當收到消息時主線程初始化相應對象使之開始處理,同時返回,這樣主線程就可以始終更新界面顯示並接收外界發來的消息,達到同時對多個對象的控制;另一方面,各個對象在處理完消息後需要通知GUI主線程。對於這個問題,可以利用第3節中的用戶自定義事件的方法,在主線程中安裝一個事件過濾器,來捕捉從各個對象中發來的自定義事件,然後發出信號調用主線程中的一個槽函數。 另外,也可以利用Qt中的定時器機制實現類似的功能,而又不必擔心Thread-safe問題。下面就是有關的代碼部分: 在用戶定義的Server類中創建和啟動了定時器,並利用connect函數將定時器超時與讀取設備文件數據相關聯:
Server:: Server(QWidget *parent) : QWidget(parent)
{
readTimer = new QTimer(this);   //創建並啟動定時器
   connect(readTimer, SIGNAL(timeout()), this, SLOT(slotReadFile()));   //每當定時器超時時調用函數slotReadFile讀取文件
   readTimer->start(100);
}
slotReadFile函數負責在定時器超時時,從文件中讀取數據,然後重新啟動定時器:
int Server::slotReadFile()    // 消息讀取和處理函數
{
  readTimer->stop();     //暫時停止定時器計時
  ret = read(file, buf );   //讀取文件
if(ret == NULL)
{    readTimer->start(100);     //當沒有新消息時,重新啟動定時器
    return(-1);
}
  else
       根據buf中的內容將消息分發給各個相應的對象處理……;
readTimer->start(100);    //重新啟動定時器
}
  

  

在該程序中,利用了類似輪循的方式定時對用戶指定的設備文件進行讀取,根據讀到的數據內容將信息發送到各個相應的對象。用戶可以在自己的GUI主線程中創建一個Server類,幫助實現底層的消息接收過程,而本身仍然可以處理諸如界面顯示的問題。當各個對象完成處理後,通過重新啟動定時器繼續進行周期性讀取底層設備文件的過程。當然,這種方法適合於各對象對事件的處理時間較短,而底層設備發來消息的頻率又相對較慢的情況。在這種情況下,上述方法完全可以滿足用戶的需求,而又避免了處理一些與線程並發有關的復雜問題。

linux定時器的實現方法