27 Şubat 2016 Cumartesi

Timer

.Net
Windows'ta sistem saati elle değiştirilince, kurulu bekleyen timer'lar kendilerini yeniden kurmazlar. Dolayısıyla karışıklıklar olabilir. Durumu düzeltmek için SystemEvents.TimeChanged event'i dinlenerek timer'ları tekrar kurmak gerekebilir.

System.Windows.Forms.Timer
Konuyu Timer Sınıfları yazısına taşıdım.

System.Timers.Timer
Konuyu Timer Sınıfları yazısına taşıdım.

System.Threading.Timer
Konuyu Timer Sınıfları yazısına taşıdım.

Java
Konuyu Java Timer Sınıfları yazısına taşıdım.

QT
QTimer aslında sadece her QObject sınfının sahip olduğu QObject::startTimer yeteneğini daha rahat kullanmamızı sağlayan bir sınıf. Timers başlıklı QT dokümantasyonunu okumakta fayda var.

POSIX
Posix ile timer yaratmak için bir kaç yöntem var.

alarm() yöntemi
alarm kullanırsak tek thread'li bir timer elde ederiz. Alarmı her seferinden tekrar kurmak gerekir. Örnek'te 3 defa 1 saniye aralıkla çalan bir alarm var.

timer_create yöntemi
timer_create(), timer_settime(),timer_connet(),timer_delete() beraber kullanılıyorlar.İlki timer nesnesini yaratır, ikincisi başlatır, sonuncusu ise timer nesnesini kapatır.

timer_create() metodunun imzası aşağıda.
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
Bu metod ile kullanılan timer_t çoğu derleyicide void * olarak tanımlı. Bu yüzden timer_delete() ile silinmesi gerekiyor.
typedef void * __timer_t;
typedef __timer_t timer_t;

timer_create metodu signal'ler ile beraber kullanılabilir veya kullanılmayabilir.

signal olmadan kullanımı
timer_connect() metodu POSIX'te yok. Bu yöntem vxWorks'te işe yarıyor.
sigevent alanına NULL geçiyoruz. Çağırılacak metod timer_connect() ile belirtiliyor. Örnek:
timer_t polltimerID;
struct itimerspec poll_time;
poll_time.it_value.tv_sec = 0;
poll_time.it_value.tv_nsec= 1000; 

poll_time.it_interval.tv_sec = 0;
poll_time.it_interval.tv_nsec= 1000; // execute it every 1us

if(timer_create (CLOCK_REALTIME, NULL, &polltimerID))
    printf("problem in timer_create(): %s",strerror(errno));

if(timer_connect (polltimerID,MyPollFunction,0))
    printf("problem in timer_connect(): %s",strerror(errno));

if(timer_settime (polltimerID, 0, &poll_time, NULL))
    printf("problem in timer_settime(): %s",strerror(errno));

signal ile kullanımı

timer_create metodunu SIGEV_SIGNAL ile kullanırsak tek thread'li bir timer elde ederiz. Eğer SIGEV_THREAD ile kullanırsak timer'ın her çalışmasında yeni bir thread içinde çalışmasını sağlarız.

setitimer
Şu satırı dahil ederiz.
#include <sys/time.h>
Bu metod eski. timer_settime kullanılmalı. Kabaca şöyle yaparız.
#include <sys/time.h>
#include <signal.h>

void alarmhandler(){
    printf("\nTimer triggered");
}

void main(){
    struct itimerval timerval;
    signal(SIGALRM, alarmhandler);
    timerval.it_value.tv_sec = 1;
    timerval.it_value.tv_usec = 0;
    timerval.it_interval.tv_sec = 30;
    timerval.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &timerval, 0);
    pause();    
}
Çağrı hata varsa -1 döner. Virtual timer olarak ta kullanılabilir. Bu timer sadece uygulama çalışırken etkindir.
setitimer(ITIMER_VIRTUAL, &timerval, NULL);
getitimer ile kalan değer alınabilir.
getitimer(ITIMER_VIRTUAL, &timerval);
timer_settime
Bu metod timer_create ile yaratılmış bir timer'ı başlatır. Başlatmadan önce delay ve interval atanması gerekir. Bu işi yapmak için aşağıdaki gibi bir metod kullanılabilir. Örnek:

void itimerspec(struct itimerspec *tsp, int seconds){
    tsp->it_value.tv_sec = seconds;
    tsp->it_value.tv_nsec = 0;
    tsp->it_interval.tv_sec = seconds;
    tsp->it_interval.tv_nsec = 0;
}

Periodic Timer - SIGEV_THREAD ile
//Thread function to be invoked when the periodic timer expires
void timeoutHandler(sigval_t info)
{
}

struct sigevent sev;
memset(&sev,0,sizeof(struct sigevent));
//notify via thread
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = timeoutHandler;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_int =20;
sev.sigev_value.sival_ptr = &timer1;//Allows handler to get ID of this timer
// Create timer based on the current system time (CLOCK_REALTIME)
timer_t timer1;
if (timer_create(CLOCK_REALTIME, &sev, &timer1) != 0)
{
    //Error
}

struct itimerspec ts;
//Set delay
ts.it_value.tv_sec =1;//Delay 1 second
ts.it_value.tv_nsec = 0;
//Set interval
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 100000000;//Expire every 10th of a second

if (-1 ==timer_settime(timer1,0,&ts,NULL))
{
    //Error
}
//2 saniye bekle
sleep(2);
//Timer'ı kapatmak için
timer_delete(timer1);

Absolute Timer - SIGEV_SIGNAL ile
Absolute timer, gelecekteki bir zamanda çalışmasını istediğimiz timer anlamına geliyor.Örneği buradan aldım

//Signal handler function to be invoked when the absolute timer expires
void sig_handler (int val)
{
    printf("The timer expired and has entered signal handler: Value: %d\n", val);
}
int main()
{
    int Ret;

    struct sigevent sig;
    sig.sigev_notify = SIGEV_SIGNAL;
    sig.sigev_signo = SIGUSR1;
    signal(SIGUSR1, sig_handler);
   
    //create a new timer.
    timer_t timerid; //Stores the ID of the timer
    Ret = timer_create(CLOCK_REALTIME, &sig, &timerid);
    if (Ret == 0)
    {
        struct timespec newtime; //Stores the current system time
        struct itimerspec in, out; //Input values for the timer
        memset(&newtime, 0, sizeof (struct timespec));
        clock_gettime(CLOCK_REALTIME, &newtime);
        in.it_value.tv_sec = newtime.tv_sec + 10;
        in.it_value.tv_nsec = 0;
        in.it_interval.tv_sec = 0;
        in.it_interval.tv_nsec = 0;
       
        //issue the absolute timer request here.
        Ret = timer_settime(timerid, 1, &in, &out);
        if(Ret == 0)
            sleep(11);
        else
            printf("timer_settime() failed with %d\n", errno);
        //delete the timer.
        timer_delete(timerid);
    }
    else
        printf("timer_create() failed with %d\n", errno);
    return Ret;
}
Win32
WIN32 Timer'ları yazısına taşıdım.

Linux
prctl
Bu metod ile timerların gruplanması kontrol ediliyor. Gecikmeyi azaltmak için aşağıdaki gibi yapılabilir.
prctl(PR_SET_TIMERSLACK, 1);

timerfd_settime
Bu metod ile select veya poll ile dinlenebilen bir timer yaratılabilir. Örnek:

//create timer
int timer_fd  =  timerfd_create(CLOCK_MONOTONIC , 0); //non-settable clock or
int timer_fd  =  timerfd_create(CLOCK_REALTIME, 0); //settable system-wide clock

//periodic timer
struct itimerspec time_period = {{10,0},{10,0}};
result = timerfd_settime(timer_fd, 0, &time_period, NULL);
Bir başka periodic timer örneği:
int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
struct itimerspec timspec;
bzero(&timspec, sizeof(timspec));
timspec.it_interval.tv_sec = 0;
timspec.it_interval.tv_nsec = nanosecondInterval;
timspec.it_value.tv_sec = 0;
timspec.it_value.tv_nsec = 1;

timerfd_settime(timerfd, 0, &timspec, 0);

//absolute timer
struct itimerspec new_value;
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
new_value.it_value.tv_sec = now.tv_sec + 10;//expire after 10 seconds
new_value.it_interval.tv_sec = 0;//interval
new_value.it_value.tv_nsec = now.tv_nsec;
          
timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL);

//select or read fd now
//...

High Resolution Timer
Buradaki örnekte hrtimer_init(), hrtimer_start() metodları gösterilmiş.

Kendi Timer Sınıfımız
Buradaki soruda kendi timer sınıfımızı yazmak istersek, ne yapabileceğimiz kabaca anlatılmış.

Tek thread'li gömülü bir yazılım yapıyorsak timer'ı çalıştıran kod öncelik olarak döngüde en başta bir yerde olmalı.

Bir diğer örnekte ise Timer Wheel yapısı anlatılmış.

Timer ve Dictionary
Bazen bir nesne için bayatlama timer'ı tutmak gerekir. Nesnenin anahtar alanı ile timer'ı eşleştiren bir Dictionary yaratılır. Nesne güncellendikçe Dictionary'den Timer bulunur ve tekrar kurulur. Nesne silinmek istenirse önce Timer nesnesi daha sonra nesne silinir.

TimeoutHandler çağrıldığı zaman nesnenin anahtar değerini de veriyor olması gerekir.




Hiç yorum yok:

Yorum Gönder