Solved

Multi callback timer under Linux and c/c++

Posted on 2004-03-25
7
3,646 Views
Last Modified: 2007-12-19
Hi!
I am looking for an way to handle in c++ and linux timers like in java (timer.schedule) or in Win32/MFC (SetTimer) with a callback after elapsed time. What about support of multiple callbacks with different times???

The SIG_ALRM/alarm does only support 1 callback with bad time resolution of 1 second. But I need multiple callbacks with short intervalls like that:

Timer t1 = new Timer (func1, 1000);
Timer t2 = new Timer (func2, 60);
...

Can anybody give me a tip??? I know how to implement with multiple threads and sleep but is there no implementation out there???

regards
martin

0
Comment
Question by:zuse01
7 Comments
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10684629
Hi zuse01,

There is no direct way (API) to do what you want ... If sleep solution is OK with you, the you can use usleep or nanosleep, but be warned that even with nanosleep, best resolution that you can expect is 10ms ... You can use sleep with pthreads to achieve what you want ...

An alternative is presented in linux kernel in the form of timer queue, though programming it might not be convenient ... dont kow if newer kernel versions still support it ...

Sunnycoder
0
 

Author Comment

by:zuse01
ID: 10684649
hi sunnycoder!

You mean
not convenient to program an interface like in java with phread and sleep
????
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10684695
zuse01,

I meant not convenient to program in the kernel using timer queues

pthread and usleep will be lot more easy to use

Sunnycoder
0
 
LVL 4

Accepted Solution

by:
oumer earned 400 total points
ID: 10685804
Since there is a penality of upto 10ms when using sleep commands in linux, if your timing constraint is very tight, you should avoid using them.

The way I will do it (actually that is how i do it on my current development project): Have a scheduler that mainatins a list of priority queue of timerhandlers, and process this priority queue forever inside the main thread of the scheduler. when a timer needs firing, call the callback method of your timer ...

I am assuming you are using c++, and the code is  not complete, and the protections may have to be changed (private, public ,...)  according to your need, here I have put all public for simplicity, if you need details, please let me know,

I have a timer handler base class

class TimerHandler
{
  struct timeval expiry;
  double periodic_expiry; //if you have periodic timer, set this to the period, otherwise it should be zero
 protected:
  void setExpirationTime(struct timeval);
  void setExpirationTime(double);
  virtual void callback()=0;
};

Depending on your need you can subclass from this TimerHandler. Or if your timers are very similar, just make =0 from the callback to make it non pure virtual and define it in your class.

And you have some scheduler class that will have a member of priority queue to hold timers that should fire ...

struct TimerHandlerComparision   //used in the priority queue to compare timers
{
  bool operator()(TimerHandler *x, TimerHandler *y)
  {
    struct timeval tx=x->getExpirationTime(), ty=y->getExpirationTime();
    return (((tx.tv_sec - ty.tv_sec)+ ((((double)(tx.tv_usec - ty.tv_usec)))/1000000) ) > 0);
    //return ((*x) > (*y));
  }
};

class Scheduler
{
  std::priority_queue<TimerHandler*,std::vector<TimerHandler*>,
TimerHandlerComparision> timeline;
  bool Register(TimerHandler*);
  void processNextEvent(void);
  void run();
};


The run method should be the entry to the scheduler's thread. inside the main method you do something like

while(true)
processnextevent();


in the processnextevent()

if (this->timeline.empty())
    {
      //do some i/o stuff, if you want or just leave it empty
     }
 else
    {
      //we have to check if there is any timer(s) that needs to fire
      TimerHandler *timer = this->timeline.top();
      gettimeofday(&temp, NULL);
      exp = timer->expiry;
      time_diff = (exp.tv_sec - temp.tv_sec)+ ((double)(exp.tv_usec - temp.tv_usec))/1000000;
      if (time_diff < = 0.0) // time has passed for the timer
      {
         timeline.pop();
           timer->callback();
        }
}

In the register method, put the timer in the priority queue, with something like ..

//add current time value to the expiration time of the timer (which was relative when the timer was created to an absolute time ....)
struct timeval temp;
gettimeofday(&temp, NULL);
 
struct timeval temp_time = t->getExpirationTime();
 double temp_time_float =temp_time.tv_sec + (((double)temp_time.tv_usec)/1000000);
temp_time_float += (temp.tv_sec + (((double)temp.tv_usec)/1000000));

t->setExpirationTime(temp_time_float);
timeline.push(t);
 
In the timerhandler's callback you can do whatever you want, for example spawn another thread to do some stuff

A typical code for the callback will be something like ....

for a non periodic timer

callback()
{
  do stuff()
}

for a periodic timer

callback()
{
   do stuff();
   this->setExpirationTime(periodic_expiry) //cause when we reach this expiry has become an absoulte value instead of realtive ...
   scheduler->register(this);
}


0
 

Expert Comment

by:neale
ID: 10689034
hi,

setitimer allow you to specify microsecond resolution.
as far as i can remeber you can only have one timer running at once, but you can easily handle this by doing something similar to that described above. Keep your timers in a queue and when a timer expires (you get SIAG_ALARM) run thru the list calling expire() on each object, then it will see if it has expired and do whatever takes your fancy.

hth
neale
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
partition customisation for kickstart file 2 104
RHEL red hat 7.3 how can I upgrade the kernel? 12 1,024
CRON expression that fires every other Tuesday 3 126
mounting drive a in a linux 14 41
Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to fix the unknown display problem in Linux Mint operating system. After installing the OS if you see Display monitor is not recognized then we can install "MESA" utilities to fix this problem or we can install additio…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
Are you ready to implement Active Directory best practices without reading 300+ pages? You're in luck. In this webinar hosted by Skyport Systems, you gain insight into Microsoft's latest comprehensive guide, with tips on the best and easiest way…

697 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question