Reputation: 1140
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:
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
Upvotes: 1
Views: 2256
Reputation: 2010
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.
Upvotes: 2