[C] éxécuter du code périodiquement

Bonjour,
Je bloque sur un petit problème en C.
En fait, je voudrais écrire une fonction qui vérifie si assez de temps s’est écoulé pour éxécuter du code.
Cette fonction, je voudrais lui donner comme seul paramètre la période.

Mon problème se pose lorsque j’utilise cette fonction pour une période de 2 secondes, puis pour une période plus grande : le code pour une période plus grande ne s’exécute jamais.

Pouvez-vous me conseiller?
Voici cette fonction :

int runevery(int sec){
    /*return 1 if enough time is elapsed
     * since last run
     * else return 0 */
    time_t new = time(NULL);
    static time_t before = 0;
    
    if ( difftime(new, before ) >= sec)
    {
        before = new;
        return(1);
    }
    else 
        return(0);
}


int main(int argc, char *argv[])
{
    for (;;sleep(1)){
    if ( runevery(3) )
        printf("3 sec elapsed\n");
    if (runevery(5))
        printf("5 sec elapsed\n"); // n'apparait jamais
    else
        printf("please wait\n");

    }
	return 0;
}

Toutes les 3 secondes tu réinitialises ton point d’ancrage (static before). C’est normal que tu n’atteignes jamais les 5 secondes. :wink:

Quant à te le corriger… Je ne suis pas certain de ce que tu veux obtenir au final. Perso j’aurais tendance à te conseiller des threads (ce qui te permet d’avoir un thread à 3 secondes et un deuxième à 5 secondes, et en plus ça simplifie le code puisque tu peux tout faire avec un bête sleep) mais pas sûr que ça soit ce que tu veux et ça entraîne d’autres problèmes (synchronisation des données partagées, bref le merdier habituel en multithread).

Si tu veux rester sur un seul thread, il faut sortir ton point d’ancrage de la fonction (static = partagé par tous les appelants, c’est de là que vient ton problème) et le passer en paramètre (pointeur pour pouvoir mettre à jour le contenu). Bien entendu tu auras besoin de 2 points d’ancrage différents donc 2 variables dans ton main().
Je te laisse chercher le reste toi-même sinon c’est pas drôle. :wink:

Non il n’est justement pas réinitialisé (toute l’instruction ne s’exécute qu’une seule fois).
Par contre moi je conseil surtout de passer par SIGALRM qui me semble mieux fais pour ça.
Par jeux j’ai fais ma propre version (et ça m’a permis de jouer avec clang qui déchire) :
pastebin.com/hMA6Miui

L’utilisation des signaux paraît plus compliqué mais c’est finalement très simple. Ici je reste sur un seul processus donc je continue de mettre un sigalrm à 1 (le pgcd de 3 et 5) mais en prenant un processus par interval tu peut mettre directement ce qu’il faut.

Non il n’est justement pas réinitialisé (toute l’instruction ne s’exécute qu’une seule fois).[/quote]
Bien sur que si il est réinitialisé, il te faut des before distincts, par exemple

[code]#include <time.h>

int runevery(time_t *before,int sec){
/*return 1 if enough time is elapsed
* since last run
* else return 0 */
time_t new = time(NULL);

if ( difftime(new, before ) >= sec)
{
    before = new;
    return(1);
}
else
    return(0);

}

int main(int argc, char *argv[])
{
time_t before3 = 0;
time_t before5 = 0;

for (;;sleep(1)){
  if ( runevery(&before3,3) )
    printf("3 sec elapsed\n");
  if (runevery(&before5,5))
    printf("5 sec elapsed\n"); // n'apparait jamais
else
    printf("please wait\n");

}

return 0;
}
[/code]

[quote]prof@debian:/tmp$ ./test
3 sec elapsed
5 sec elapsed
3 sec elapsed
5 sec elapsed
3 sec elapsed
5 sec elapsed
[/quote]

Oui c’est réinitialisé, ça j’avais bien vu le problème :slightly_smiling: . Mais je n’avais pas idée de la façon de faire ça autrement sans trop compliquer le code.
Il est presque plus simple de créer une fonction pour chaque intervalle de temps voulu.
Merci beaucoup à tous les trois! J’ai de quoi travailler avec toutes vos réponses, et c’est ce que je voulais :slightly_smiling:

Je dois pas comprendre ce sue vous dites…

[code]% less prog.c
#include <stdio.h>

int foo() {
static int value = 0;
return value++;
}

int main(int argc, char** argv) {
int i;
for (i = 0; i < 10; ++i) {
printf(“value = %d\n”, foo());
}
return 0;
}
% make prog
cc prog.c -o prog
% ./prog
value = 0
value = 1
value = 2
value = 3
value = 4
value = 5
value = 6
value = 7
value = 8
value = 9
[/code]
S’il était réinitialisé il afficherait systématiquement la même valeur (ou alors vous parlez du « before = new » ?).

Oui, il reinitialise le compteur à chaque fois qu’un seuil est atteint donc ici toutes les 3s…

Oui on parlait du before = new :slightly_smiling:

fran.b, ton code ne manquait-il pas de “*”?

int runevery(time_t *ltime, int sec){
    /* return 1 if sec elapsed since last run
     * else return 0 
    */
    time_t now = time(NULL);
    
    if ( difftime(now, *ltime ) >= sec)
    {
        *ltime = now;
        return(1);
    }
    else 
        return(0);
}

Où ça? C’est un copier du fichier test.c exécuté juste après…

Lorsque l’on change la valeur du before, ou fait la comparaison dans le if :

if ( difftime(now, *before ) >= sec) { *before = now;