OVH Cloud OVH Cloud

realiser un timer en c

5 réponses
Avatar
nicolas
bonsoir,
je suis en train de realiser un petit programme qui necessite un timer:
j aimerai realiser une action tous les x usec, tout en ecoutant l'entree
standart. J utilise donc pour cela un select.

Mon probleme est le suivant: lorsque l'utilisateur intervient, on
observe une acceleration du cycle ...
Je ne sais pas d'ou cela peut venir

Voici comment je procede:

void timer(timeval_t timeout)
{
fd_set fdset;

FD_ZERO(&fdset);
FD_SET(STDIN_FILENO, &fdset);
timeout_handler(STATE_BEFORE, NULL);
if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, timeout) == -1)
;
timeout_handler(STATE_AFTER, NULL);
if (FD_ISSET(STDIN_FILENO, &fdset) != 0)
timeout_handler(STATE_SUB, timeout);
else
timeout_handler(STATE_TIMEOUT, timeout);
}

ma boucle :

timeval_t timeout = {0, 250000};

while (1)
{
timer(&timeout);
if (timeout.tv_usec == 0)
{
do_action();
timeout.tv_user = 250000;
}
}

ma fonction timeout_handler:

void timeout_handler(int state, struct timeval *timeout)
{
static struct timeval before;
static struct timeval after;

if (state == STATE_BEFORE)
gettimeofday(&before, NULL);
else if (state == STATE_AFTER)
gettimeofday(&after, NULL);
else if (state == STATE_SUB)
{
if (timeout)
{
if (after.tv_usec - before.tv_usec >= timeout->tv_usec ||
after.tv_usec - before.tv_usec <= 0)
timeout->tv_usec = 0;
else
timeout->tv_usec -= (after.tv_usec - before.tv_usec);
}
}
else if (state == STATE_TIMEOUT)
if (timeout)
timeout->tv_usec = 0;
}

merci d avance pour vos reponses.

5 réponses

Avatar
Antoine Leca
nicolas wrote:
je suis en train de realiser un petit programme qui necessite un
timer: j aimerai realiser une action tous les x usec, tout en
ecoutant l'entree standart. J utilise donc pour cela un select.
Mon probleme est le suivant: lorsque l'utilisateur intervient, on
observe une acceleration du cycle ...
Je ne sais pas d'ou cela peut venir


Essayer sur fr.comp.os.unix?

Les problèmes en postant ici, c'est que
-- une résolution de 1 µs en C, ce n'est pas toujours facile
-- tv_user est un truc spécifique à ta machine
-- la fonction select() est hautement liée à un environnement (sockets) qui
n'est pas disponible partout

donc il nous est impossible de facilement tester ton programme dans des
environnements différents pour comprendre pourquoi il y a un problème (en
d'autres termes, ce n'est pas un programme portable).


La seule chose évidente est que tu manipules les tv_usec sans gérer
proprement les retenues (quand le tv_sec change)


Sinon, pour l'aspect style de programmation:

-- timeval_t n'est pas très standardisé en C, tu devrais t'obliger à
toujours écrire struct timeval (en supposant que c'est ce que fait ton
environnement)
-- l'initialisation de timeout fait une supposition sur l'ordre des membres
de la structure, c'est souvent vrai mais cela peut être faux aussi.


Antoine

Avatar
Harpo
nicolas wrote:

bonsoir,
je suis en train de realiser un petit programme qui necessite un
timer: j aimerai realiser une action tous les x usec, tout en ecoutant
l'entree
standart. J utilise donc pour cela un select.

Mon probleme est le suivant: lorsque l'utilisateur intervient, on
observe une acceleration du cycle ...
Je ne sais pas d'ou cela peut venir


Typiquement HS, mais je ne sais pas s'il y a de meilleurs forum .fr
pour poser cette question.

Ici je ne comprends pas l'interêt du if () ;

if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, timeout) == -1)
;


Il est possible que le problème vienne d'ici :

else if (state == STATE_SUB)
{
if (timeout)
{
if (after.tv_usec - before.tv_usec >= timeout->tv_usec ||
after.tv_usec - before.tv_usec <= 0)
timeout->tv_usec = 0;
else


surtout d'ici :

timeout->tv_usec -= (after.tv_usec - before.tv_usec);
}
}


la valeur de timeout->tv_usec peut être modifiee par select() (sous
GNU/Linux, SVID) ou non (BSD) pour refléter le temps restant à
attendre, ce qui fait que sur un Linux tu remets la durée d'attente à
une valeur moindre que celle voulue. Il est préférable de considérer
que la valeur de timeout->tv_usec est indéterminée après select()

La solution est soit :
1- de passer à timeout_handler() dans une variable la valeur du tempo et
de recalculer timeout->tv_usec à partir de cette valeur.
2- installer BSD ;-)

Plus de précisions par 'info libc' dans la rubrique 'Waiting for I/O' et
les rubriques concernant les signaux.

Avatar
Harpo
Antoine Leca wrote:

-- la fonction select() est hautement liée à un environnement
(sockets) qui n'est pas disponible partout


Ce serait plutôt les sockets qui sont liés à select() car on utilise
généralement select() avec les sockets. Mais select() est un moyen
classique sur les unix pour écouter sur plusieurs file descriptors non
nécessairements liés à des sockets. Préférer quand même pselect() qui
est plus sophistiqué et standart POSIX IEEE je-sais-plus.

donc il nous est impossible de facilement tester ton programme dans
des environnements différents pour comprendre pourquoi il y a un
problème (en d'autres termes, ce n'est pas un programme portable).


C'est certain, mais il devrait pouvoir tourner sur une majorité d'unix.

Sinon, pour l'aspect style de programmation:

-- timeval_t n'est pas très standardisé en C, tu devrais t'obliger à
toujours écrire struct timeval (en supposant que c'est ce que fait ton
environnement)


En effet, la doc dit 'struct timeval' au moins sur GNU/Linux. Il y a
plus de chance que ce soit défini sur d'autres implémentation.

Avatar
nicolas
Harpo wrote:
nicolas wrote:


bonsoir,
je suis en train de realiser un petit programme qui necessite un
timer: j aimerai realiser une action tous les x usec, tout en ecoutant
l'entree
standart. J utilise donc pour cela un select.

Mon probleme est le suivant: lorsque l'utilisateur intervient, on
observe une acceleration du cycle ...
Je ne sais pas d'ou cela peut venir



Typiquement HS, mais je ne sais pas s'il y a de meilleurs forum .fr
pour poser cette question.


oui moi non plus en fait :(


Ici je ne comprends pas l'interêt du if () ;


if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, timeout) == -1)
;



Il est possible que le problème vienne d'ici :


else if (state == STATE_SUB)
{
if (timeout)
{
if (after.tv_usec - before.tv_usec >= timeout->tv_usec ||
after.tv_usec - before.tv_usec <= 0)
timeout->tv_usec = 0;
else



surtout d'ici :


timeout->tv_usec -= (after.tv_usec - before.tv_usec);
}
}



la valeur de timeout->tv_usec peut être modifiee par select() (sous
GNU/Linux, SVID) ou non (BSD) pour refléter le temps restant à
attendre, ce qui fait que sur un Linux tu remets la durée d'attente à
une valeur moindre que celle voulue. Il est préférable de considérer
que la valeur de timeout->tv_usec est indéterminée après select()

La solution est soit :
1- de passer à timeout_handler() dans une variable la valeur du tempo et
de recalculer timeout->tv_usec à partir de cette valeur.

2- installer BSD ;-)


je suis sous BSD :)


Plus de précisions par 'info libc' dans la rubrique 'Waiting for I/O' et
les rubriques concernant les signaux.



Merci a tous les deux pour vos reponses je vais continuer a chercher ;)


Avatar
Harpo
nicolas wrote:


La solution est soit :
1- de passer à timeout_handler() dans une variable la valeur du tempo
et de recalculer timeout->tv_usec à partir de cette valeur.

2- installer BSD ;-)


je suis sous BSD :)


Euh ... Ce n'est donc pas ça.
Le conseil 1- peut être quand même interessant pour plus de portabilité,
mais la portabilité d'un bug n'est peut-être pas le plus urgent.