The usecase
I'm writing a C program which needs multiple timers. I had first written a fast prototype which started a pthread for every timer. Just a simple while-loop with a sleep command because 1 second resolution is enough.
But with more than 10 timers it's not a very efficient nor production grade code quality. Therefore I wanted to use an eventloop. I've read several times about libuv and thought to give it a try.
So my idea was simple. Have 1 timer thread which runs the timer eventloop and add and remove timers on the fly. The timers are very simple countdown timers which execute a function pointer when they reach 0 and which can be canceled. So no repetition is needed.
The problem
I think the real problem here is documentation, the libuv docs simply aren't very clear on how to achieve this. So I think the code I currently have is rubbish. Let me walk you through it.
At the beginning of my program I'm starting a phtread with the following entrypoint:
static void* _uv_loop_thread_entry_point(void *args)
{
/* Initialize the timer event loop */
timer_event_loop = malloc(sizeof(uv_loop_t));
uv_loop_init(timer_event_loop);
/* Keep running the eventloop */
while(uv_run(timer_event_loop, UV_RUN_DEFAULT) == 0) {
/* Wait 1 second for new handles */
sleep(1);
};
/* The timer event loop has stopped, free all resources */
uv_loop_close(timer_event_loop);
free(timer_event_loop);
return NULL;
}
Than whenever I want to use a timer I would do the following:
uv_timer_init(timer_event_loop, uv_timer);
uv_timer_start(uv_timer, timeout_ms, ??);
Now I have several questions:
How to use the timer without repetition
Where do I set the callback function for this timer
How can I know how much time is left in this timer
I can really use some help on this subject.
Update 1
Ok, I'm making some progress and it basically works. The libuv event loop runs in a separate thread. And to already answer some of my questions:
When the last argument in uv_timer_start is 0 the timer will not repeat itself.
The callback for the timer timeout event is the second argument of uv_timer_start
I don't yet know the best answer to my third question. But for now I keep track of the time when my timer has started and the current time and take the difference. I than substract the difference from the total time of the timer to know how long it will take before the timer will end.
I would still like to know if my uv_run implementation is correct.
Kind regards,
Daan
You are playing in undefined behavior territory. libuv is not thread-safe see the docs here So while running the loop in a thread is ok, creating a timer in another thread while the loop is running is not.
You can still do it by using a uv_async_t handle and a semaphore: uv_async_send is thread-safe, so you would call it from the outside, stop the loop and signal a semaphore. The calling thread would wait until the semaphore is signaled. At this point the loop is stopped, so it's ok to create a new timer and add it.
There is no API to know how much time a timer has left.
If all you need is a loop to control some timers libuv might be overkill. You could use timerfd if you're on Linux, or a hand-built event loop which only does timers on top of select for example.
Related
sleep() blocks the running thread in C given x amount of seconds.
If I'm not mistaking, this can be implemented in 2 ways. Either go in an infinite loop and check the current time with BIOS, if time>=timeout then end the loop.
Second way is to use a timer in CPU and let the timer do the counting async and not block the CPU thread.
Am I correct about the above 2 methods? if so why doesn't C have a function to implant the second way so we can have non-blocking "delays"?
There's another way, which is the one which is usually behind a call to sleep(): tell the kernel scheduler to remove this process from the runnable set until the time has expired.
For the function which sets a timer and tells you when it is finished, you can start by looking at alarm() and pause(). Those aren't in the standard C library, but they have been in Posix for a very long time.
On Windows, you could look at SetTimer.
I use a workqueue to defer work. Since I know beforehand how many work-items I want to be processed, I initialize an atomic variable with that number. I set my process current state to to TASK_INTERRUPTIBLE, submit all the work and then send the process to sleep with schedule(). In each work routine at the end the atomic variable is decreased and tested. If the last work-item has been completed the process is woken up.
Is there a better way to do this?
And my actual question: if i want to defer work from within a work routine itself, can I achieve the same thing? For the process I pass current to the work routine, which is then used as parameter for the wake up call. Can I send to sleep and wake up a work routine in the same way, too?
EDIT: I know tried it the same way, by passing current from within the workqueue routine to the next workqueue routine. As a second way I set up a struct completion and passed it to the next workqueue routine. Both worked. But I'm not sure if it works by chance or if it is correct.
I'm using a timer that can fire up to 5000 times a second. At the same time, the process that is running the timer will have spawned 32 threads of its own. Every time the timer fires, I want my threads to do something.
I can do this using any of the sigevent types (pulse, signal, or create a thread that sets a variable the other threads watch for), but I'm not sure which one would be most efficient.
I know threads are probably a bad idea as they are expensive and making so many every second will probably cause performance issues, so any ideas?
I would like it to perform the action ASAP once the timer has fired. So what's the best type of event to use?
EDIT: Forgot to mention, this is coded in C
I have created a timer using the simple "timer_create". The timer is created using SIGEV_THREAD. That is when the timer expires, there is a call to the timer thread function.
How timer_create works is, suppose assume: expiry=3 secs and timer interval is 1 ns, then the timer keeps ticking every 1 ns until expiry reaches. Once the timer expires, from that instance it keeps on hitting the timer thread function after every 1 ns (timer interval). And keeps on creating one thread per hit till the timer is deleted.
I don't want this to happen, i want once the timer expires, it should go and hit the thread function only once.
How can i achieve this? Can we put any option in timer_create? If not any other timer API?
Thanks a lot in advance
I think this is an implementation flaw in the glibc implementation of POSIX timers. There is certainly no way the timer_getoverrun function, which is critical for realtime usage, can work in the glibc implementation, since it returns from the kernel the overrun count for the "current" expiration, but when multiple expiration events are running in parallel, "current" makes no sense. There are also serious issues with resource exhaustion and dropped expiration events which make the implementation unusable for realtime purposes. For example, in nptl/sysdeps/unix/sysv/linux/timer_routines.c:
struct thread_start_data *td = malloc (sizeof (*td));
/* There is not much we can do if the allocation fails. */
...
In the Linux man page for sigevent, you see for SIGEV_THREAD:
Among the implementation possibilities here are that each timer notification could result in the creation of a new thread, or that a single thread is created to receive all notifications.
The latter is the only choice that could provide correct realtime semantics, but for some reason, glibc did not take this choice.
Here is a possible workaround:
Choose a realtime signal, block that signal before creating any threads, and setup your timer to use that signal with SIGEV_SIGNAL. Now, create a thread for handling your timer(s), and loop on sigwaitinfo, then call your handler function each time it returns. This is actually one possible implementation (and the most-correct implementation) of SIGEV_THREAD which glibc should be using.
Another possibility: there is exactly one synchronization-related, non-syscall-invoking, async-signal-safe function in POSIX: sem_post. Thus it may be possible to make a signal handler (as opposed to getting the signal from sigwaitinfo) synchronize with another thread for the purpose of delivering timer events. But I haven't worked out the details, and it seems like it may be difficult or impossible still.
Just set timer interval to 0 and expiry to whatever you want. Your timer will expire once (and thread created and run) and then stay disarmed.
gcc 4.4.3 c89
I have a event loop that runs in a separate thread.
My design is like this below, just sample code to help explain.
I need to somehow wait for the initialization to complete before I can make a call to the get_device_params.
I did put a usleep for 3 seconds just before the call to the get_device_params, but I don't really want to block.
Many thanks for any suggestions,
void* process_events(void *data)
{
switch(event_type)
{
case EVT_INITIALIZED:
/* Device is now initialized */
break;
}
}
int main(void)
{
/* Create and start thread and process incoming events */
process_events();
/* Initialize device */
initialize_device();
/* Get device parameters */
/* However, I cannot run this code until initialization is complete */
get_device_params();
return 0;
}
If this separate thread is a POSIX thread (i.e. you're on a typical UNIX platform), then you can use pthread conditional variables.
You call pthread_cond_wait() in the waiting thread. When the init thread finishes its work, you call pthread_cond_signal(). In my opinion that's a canonical way to wait for initialization in another thread.
I need to somehow wait for the initialization to complete before I can make a call to the get_device_params.
Since you apparently have some sort of a FSM inside the process_events(), and it why ever runs in a separate thread, you shouldn't do anything from the main thread with the device.
In other words, logically, call to the get_device_params(); should be placed inside the FSM, on the event that the device is initialized EVT_INITIALIZED which I presume is triggered by the initialize_device().
Alternatively, you can create second FSM (possibly in another thread) and let the process_events() (the first FSM) after it has finished its own processing, forward the EVT_INITIALIZED event to the second FSM. (Or initialize_device() could send the event to the both FSMs simultaneously.)
To me it seems (from the scarce code you have posted) that your problem is that you try to mix sequential code with an event based one. Rule of thumb: in event/FSM based application all code should run inside the FSM, being triggered by an event; there should be no code which may run on its own outside of the FSM.
If it were me, I would probably use a barrier. In main you can call pthread_barrier_init, indicating that you have 2 threads. Then, in main call pthread_barrier_wait, to wait on the barrier you initialized, after calling your device initialization function. Finally, in the device thread, after you initialize your device, you can call pthread_barrier_wait on the same barrier and when both threads are waiting, the barrier will have been satisfied, so both threads will continue. I find barriers easier to use than condition variables sometime, but I'm sure that's an issue of preference.