tags:

views:

816

answers:

5
+1  Q: 

C++ Timers in Unix

We have an API that handles event timers. This API says that it uses OS callbacks to handle timed events (using select(), apparently).

The api claims this order of execution as well: readable events writable events timer events

This works by creating a point to a Timer object, but passing the create function a function callback:

Something along these lines:

Timer* theTimer =  Timer::Event::create(timeInterval,&Thisclass::FunctionName);

I was wondering how this worked?
The operating system is handling the timer itself, and when it sees it fired how does it actually invoke the callback? Does the callback run in a seperate thread of execution?

When I put a pthread_self() call inside the callback function (Thisclass::FunctionName) it appears to have the same thread id as the thread where theTimer is created itself! (Very confused by this)

Also: What does that priority list above mean? What is a writable event vs a readable event vs a timer event?

Any explanation of the use of select() in this scenario is also appreciated.

Thanks!

+1  A: 

At a guess, the call to create() stores the function pointer somewhere. Then, when the timer goes off, it calls the function you specified via that pointer. But as this is not a Standard C++ function, you should really read the docs or look at the source to find out for sure.

Regarding your other questions, I don't see mention of a priority list, and select() is a sort of general purpose event multiplexer.

anon
+1  A: 

This looks like a simple wrapper around select(2). The class keeps a list of callbacks, I guess separate for read, write, and timer expiration. Then there's something like a dispatch or wait call somewhere there that packs given file descriptors into sets, calculates minimum timeout, and invokes select with these arguments. When select returns, the wrapper probably goes over read set first, invoking read callback, then write set, then looks if any of the timers have expired and invokes those callbacks. This all might happen on the same thread, or on separate threads depending on the implementation of the wrapper.

You should read up on select and poll - they are very handy. The general term is IO demultiplexing.

Nikolai N Fetissov
A: 

A readable event means that data is available for reading on a particular file descriptor without blocking, and a writable event means that you can write to a particular file descriptor without blocking. These are most often used with sockets and pipes. See the select() manual page for details on these.

A timer event means that a previously created timer has expired. If the library is using select() or poll(), the library itself has to keep track of timers since these functions accept a single timeout. The library must calculate the time remaining until the first timer expires, and use that for the timeout parameter. Another approach is to use timer_create(), or an older variant like setitimer() or alarm() to receive notification via a signal.

You can determine which mechanism is being used at the OS layer using a tool like strace (Linux) or truss (Solaris). These tools trace the actual system calls that are being made by the program.

mark4o
+1  A: 

Quite likely there's a framework that works with a typical main loop, the driving force of the main loop is the select call.

select allows you to wait for a filedescriptor to become readable or writable (or for an "exception" on the filedeescriptor) or for a timeout to occur. I'd guess the library also allow you to register callbacks for doing async IO, if it's a GUI library it'll get the low primitive GUI events via a file descriptor on unixes.

To implement timer callbacks in such a loop, you just keep a priority queue of timers and process them on select timeouts or filedescriptor events.

The priority means it processes the file i/o before the timers, which in itself takes time, could result in GUI updates eventually resulting in GUI event handlers being run, or other tasks spending time servicing I/O.

The library is more or less doing

for(;;) {
  timeout = calculate_min_timeout();
  ret = select(...,timeout); //wait for a timeout event or filedescriptor events
  if(ret > 0) {
    process_readable_descriptors();
    process_writable_descriptors();
  }
  process_timer_queue();  //scan through a timer priority queue and invoke callbacks
}
nos
A: 

Because of the fact that the thread id inside the timer callback is the same as the creator thread I think that it is implemented somehow using signals.

When a signal is sent to a thread that thread's state is saved and the signal handler is called which then calls the event call back. So the handler is called in the creator thread which is interrupted until the signal handler returns.

Maybe another thread waits for all timers using select() and if a timer expires it sends a signal to the thread the expired timer was created in.

rstevens