whileone
whileone

Reputation: 2815

Restart the timer in select() of socket programming

I want to use select() to receive update from other server and also send out periodic messages. Consider the following set up:

while(1){ select(... timeout = 5 seconds); // some other code}

If I receive update at t = 2 seconds, then select() will return and corresponding statement will be executed. When the next loop begins, timeout will be set to 5 seconds again. However, it should be 5 - 2 = 3 seconds. Is there a way to update the timer with the right time?

I thought about to manually start a timer righr before select(), however this timer might not be synchronous with the one used in select(). And will cause other potential problems.

Upvotes: 2

Views: 2583

Answers (3)

brian beuning
brian beuning

Reputation: 2862

When your app gets a little more complicated, you may have multiple timers with different timeout intervals. We do. Here is how we handle it.

Each timer has a timer object with a time_t of when the timer expires. We store all the timers in a heap data structure, so the soonest timer to expire is at the root of the heap. Before doing a select() we fetch the root of the heap, and subtract the current time from the timer's expiration time and use that delta as the timeout to the select() call.

Timer * t = heap->Root();
time_t now = time(0);
timeval tv;
tv.tv_sec = t->when - now;
tv.tv_usec = 0;
select( ... & tv );

Upvotes: 1

jxh
jxh

Reputation: 70422

According to the select man page:

On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1-2001 permits either behaviour.)

So, you just simply reuse the timeout variable. You only reset its value when you really time-out.

As the warning suggests, relying on this behavior makes for a porting problem, so if you rely on this behavior, make sure you document it so that the right thing is done when porting the code.

Upvotes: 3

Michal Rus
Michal Rus

Reputation: 1848

Just remember time() in a variable before you call select(), get another time() when select() returns and... in the next while(1) iteration use not 5, but 5 - difference_between_times for timeout value.

Perhaps you'd want to use new_timeout = 5 - difference_between_times % 5, so that if your operation after select returns takes longer than 5 seconds... you still set the timeout in 5 sec interval.

You probably should use not seconds, but some more granular time unit. And think whether above is the behaviour you really want (with modulo). Maybe when difference_between_times > 5, you should wait just for 5 sec. Do as you wish, but you get the idea.

Upvotes: 1

Related Questions