IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Problème pthread_cancel et printf


Sujet :

C

  1. #1
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut Problème pthread_cancel et printf
    Bonjour,

    Je débute en threads C, et j'ai un petit problème d'annulation de threads.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
     
    void * my_routine(void *arg) {
      int i;
      for (i = 0; i < 10; i++) {
        printf("%d\n", i);
      }
      return NULL;
    }
     
    int main(int argc, char *argv[]) {
      pthread_t thread;
      int ret = pthread_create(&thread, NULL, my_routine, NULL);
      usleep(20);
      pthread_cancel(thread);
      pthread_join(thread, NULL);
      return 0;
    }

    De temps en temps, le printf n'affiche pas la bonne valeur au moment de l'annulation :
    Comment l'éviter ?

    pthread_cancel serait-il l'équivalent de Thread.stop() en Java : il ne faut jamais l'utiliser ?

  2. #2
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Bonjour,

    ça me semble plus être un problème au niveau du printf utilisé dans un environnement multi-thread, mais je n'en suis pas certain, quelque chose du genre le cancel arrive en plein milieu du printf ...

    sinon en ce qui concerne ton code, juste quelques remarques :

    int main(char *argv[]) { n'est pas correct. Si tu n'utilises pas les arguments passés en ligne de commande int main(void) {, ou si tu les utilises int main(int argc, char *argv[]) {. tu fais du java toi

    int ret = pthread_create(&thread, NULL, my_routine, NULL); c'est toujours mieux de vérifier la valeur de retour de ce genre d'appel et gérer les erreurs éventuelles.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void * my_routine(void *arg) {
      int i;
      for (i = 0; i < 10; i++) {
        printf("%d\n", i);
      }
    }
    Cette fonction doit retourner une valeur et aucun return ... le comportement de ton programme n'est pas défini dans ce cas. Ici tu peux simplement rajouter un return NULL;.

    Je ne connais pas les problèmes liés à l'utilisation de Thread.stop() en java, mais avec les pthreads il n'y a, a priori, pas de problèmes pour utiliser pthread_cancel ... peut-être des détails (comme tous les threads ne sont pas interruptibles) mais ils sont documentés dans la man page.

  3. #3
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par kwariz Voir le message
    int main(char *argv[]) { n'est pas correct. Si tu n'utilises pas les arguments passés en ligne de commande int main(void) {, ou si tu les utilises int main(int argc, char *argv[]) {. tu fais du java toi
    Oui, faute d'inattention, j'ai oublié le argc, normalement je mets argc et argv. Je ne savais pas qu'on pouvait mettre int main(void) (par contre je savais qu'on pouvait mettre int main() en C k&r). J'ai corrigé.

    Citation Envoyé par kwariz Voir le message
    int ret = pthread_create(&thread, NULL, my_routine, NULL); c'est toujours mieux de vérifier la valeur de retour de ce genre d'appel et gérer les erreurs éventuelles.
    Tout-à-fait. Mais pour un bête code de test, la flemme ^^

  4. #4
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    J'ai ajouté un usleep(500000) (500ms) à la fin. Ainsi, on peut voir que le numéro dupliqué est affiché après la pause, comme si quelque chose restait quelque part après l'annulation du printf, et qu'il était flushé à la fin…

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
     
    void * my_routine(void *arg) {
      int i;
      for (i = 0; i < 10; i++) {
        printf("%d\n", i);
      }
      return NULL;
    }
     
    int main(void) {
      pthread_t thread;
      int ret = pthread_create(&thread, NULL, my_routine, NULL);
      usleep(20);
      pthread_cancel(thread);
      pthread_join(thread, NULL);
      usleep(500000);
      return 0;
    }

  5. #5
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Oui, ce «bug» provient du fait que tu interromps printff en plein milieu de son boulot.
    Essaye par exemple dans ta boucle for de rendre ton printf insensibles aux interruptions et d'ajouter un [codeinline]usleep[codeinline] pour ralentir le tout et avoir*un point où on peut traiter le cancel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void * my_routine(void *arg) {
      int i;
      for (i = 0; i < 1000; i++) {
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        printf("%d\n", i);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        usleep(2);
      }
     
      return NULL;
    }
    Rallonge aussi le usleep du main.

  6. #6
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Je comprends bien, mais pourquoi printf est-il un cancellation point s'il ne faut pas l'utiliser tel quel même quand le canceltype du thread est PTHREAD_CANCEL_DEFERRED?

  7. #7
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    printf n'est pas un cancellation point mais en contient un, certainement un write.
    Enfin je suppose en décryptant la doc posix concernant ce point.
    Dans celle-ci on a une liste de fonctions qui sont des cancellation points obligatoirement (printf n'en fait pas partie), et d'autres qui peuvent en être un (dont printf).

  8. #8
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Merci beaucoup, c'est plus clair.

    Cependant, "qui peuvent en être un": soit c'est en un, soit non. Dans le premier cas, ça doit laisser l'état cohérent lors de l'annulation. Dans le second cas, pas de problèmes.

    Ça "en contient un" est sans doute la raison technique, mais est-ce le comportement attendu ?

  9. #9
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Je pense qu'il faut comprendre le "peut en être un" par "selon l'implémentation, c'en est un"

  10. #10
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Oui, mais si ça en est un, ça doit en être un "vrai", pas un qui laisse l'état inconsistant.

  11. #11
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Citation Envoyé par ®om Voir le message
    Ça "en contient un" est sans doute la raison technique, mais est-ce le comportement attendu ?
    C'est une bonne question ... à laquelle je n'ai pas vraiment de réponse.
    Tout comme toi je trouve le comportement au minimum étrange et inattendu dans mon esprit du coup effectivement j'assimilerais ça effectivement à un «bug».
    En gros le printf est interrompu en plein boulot, et le buffer de sorti est marqué sale (=à émettre) avant d'avoir pu être rempli correctement. Du coup au flush suivant le buffer est émis alors qu'il est dans un état indéterminé. Ce qui explique le comportement «le doublon n'est émis qu'à la fin du programme si aucun flush n'est fait avant», «il n'est pas émis si on provoque un sigfault délibérément après le join» ...
    Maintenant pour savoir si c'est correct (en un sens), il faudrait faire le test en monothread avec des signaux qui interrompent un printf si le comportement est identique alors oui c'est normal (ce qui peut sembler ridicule).

    Pour info, je n'ai pas trouvé d'équivalent dans la bug db de glibc.

Discussions similaires

  1. ProbLème avec fonction printf
    Par snipre dans le forum Langage
    Réponses: 2
    Dernier message: 08/01/2009, 13h20
  2. Problème d'affichage - printf
    Par helio500 dans le forum Débuter
    Réponses: 2
    Dernier message: 02/09/2008, 21h25
  3. Problème sur utilisation printf
    Par xxxvanouxxx dans le forum Linux
    Réponses: 6
    Dernier message: 08/08/2008, 23h33
  4. problème d'affichage avec printf
    Par sorari dans le forum C++
    Réponses: 12
    Dernier message: 08/03/2005, 18h30
  5. Problème a l'affichage dans la console (printf)
    Par PhoneKilleR dans le forum C
    Réponses: 21
    Dernier message: 23/09/2003, 17h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo