Issue
I use timerfd
with zmq.
How can I use timerfd_create
and timerfd_set
to wait one second for the timer (href="https://man7.org/linux/man-pages/man2/timerfd_create.2.html" rel="nofollow noreferrer">https://man7.org/linux/man-pages/man2/timerfd_create.2.html)?
I have looked through the link but I still do not get how I can initilize a timer that waits one second per tick with create and set. This is exactly my task:
We start a timer with
timerfd_create()
, which is 1 / sec. ticking. When setting a timer with timer_set_(..)
a counter is simply incremented, which is decremented with every tick. When the counter reaches 0, the timer has expired.
In this project we have a function timer _ set _()
, where the timer is set with the function timerfd_create and timerfd_settimer()
. I hope you can help me.
This is my progress (part of my code):
struct itimerspec timerValue;
g_items[n].socket = nullptr;
g_items[n].events = ZMQ_POLLIN;
g_items[n].fd = timerfd_create(CLOCK_REALTIME, 0);
if(g_items[n].fd == -1 ){
printf("timerfd_create() failed: errno=%d\n", errno);
return -1;
}
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
timerfd_settime(g_items[n].fd, 0, &timerValue, NULL);
Solution
The question appears about setting correctly the timeouts of the timer.
With the settings
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
You are correctly setting the initial timeout to 1s (field timerValue.it_value
). But you are also setting a periodic interval of 1s, and you didn't mention the will to do it.
About the timeouts
This behavior is described by the following passage of the manual:
int timerfd_create(int clockid, int flags);
new_value.it_value
specifies the initial expiration of the timer, in seconds and nanoseconds. Setting either field ofnew_value.it_value
to a nonzero value arms the timer.
Setting both fields ofnew_value.it_value
to zero disarms the timer.
Setting one or both fields ofnew_value.it_interval
to nonzero values specifies the period, in seconds and nanoseconds, for repeated timer expirations after the initial expiration. If both fields ofnew_value.it_interval
are zero, the timer expires just once, at the time specified bynew_value.it_value
.
The emphasis on the last paragraph is mine, as it shows what to do in order to have a single-shot timer.
The benefits of timerrfd
. How to detect timer expiration?
The main advantage provided by timerfd
is that the timer is associated to a file descriptor, and this means that it
The information contained in the other answer about read()
is valid as well: let's just say that, even using functions such as select()
, read()
function will be required in order to consume data in the file descriptor.
A complete example
In the following demonstrative program, a timeout of 4 seconds is set; after that a periodic interval of 5 seconds is set.
The good old select()
is used in order to wait for timer expiration, and read()
is used to consume data (that is the number of expired timeouts; we will ignore it).
#include <stdio.h>
#include <sys/timerfd.h>
#include <sys/select.h>
#include <time.h>
int main()
{
int tfd = timerfd_create(CLOCK_REALTIME, 0);
printf("Starting at (%d)...\n", (int)time(NULL));
if(tfd > 0)
{
char dummybuf[8];
struct itimerspec spec =
{
{ 5, 0 }, // Set to {0, 0} if you need a one-shot timer
{ 4, 0 }
};
timerfd_settime(tfd, 0, &spec, NULL);
/* Wait */
fd_set rfds;
int retval;
/* Watch timefd file descriptor */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(tfd, &rfds);
/* Let's wait for initial timer expiration */
retval = select(tfd+1, &rfds, NULL, NULL, NULL); /* Last parameter = NULL --> wait forever */
printf("Expired at %d! (%d) (%d)\n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
/* Let's wait (twice) for periodic timer expiration */
retval = select(tfd+1, &rfds, NULL, NULL, NULL);
printf("Expired at %d! (%d) (%d)\n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
retval = select(tfd+1, &rfds, NULL, NULL, NULL);
printf("Expired at %d! (%d) (%d)\n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
}
return 0;
}
And here it is the output. Every row contains also the timestamp, so that the actual elapsed time can be checked>
Starting at (1596547762)...
Expired at 1596547766! (1) (8)
Expired at 1596547771! (1) (8)
Expired at 1596547776! (1) (8)
Please note:
- We just performed 3 reads, for test
- The intervals are 4s + 5s + 5s (initial timeout + two interval timeouts)
- 8 bytes are returned by
read()
. We ignored them, but they contained the number of the expired timeouts
Answered By - Roberto Caboni Answer Checked By - Candace Johnson (WPSolving Volunteer)