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

Threads & Processus C++ Discussion :

pthread_cancel et fonctions bloquantes


Sujet :

Threads & Processus C++

  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 274
    Points : 176
    Points
    176
    Par défaut pthread_cancel et fonctions bloquantes
    Bonjour,

    j'imagine que ce problème a du être posé de nombreuses fois (même si là j'ai posté dans la rubrique c++ alors que j'utilise pthread (en fait je fais un mélange, je ne sais pas pourquoi je n'ai pas utilisé std::thread, enfin cela ne change rien au problème)), et j'ai effectué quelques recherches à ce propos, seulement je préfère être sûr de ne pas faire de choses immondes. Le projet en question n'a pas grand intérêt, juste une application client/serveur capable d'envoyer à certaines adresses un fichier et de recevoir un fichier en provenance de certaines adresses.
    Comme d'habitude, on se retrouve confronté à utiliser des threads dans tous les sens, que ce soit pour les connexions, les acceptations, les envois, les réceptions etc ... (enfin, on peut faire autrement mais c'est ce que je trouve le plus pratique et portable).
    Voilà mon problème (illustré sur la fonction d'acceptation), je poste un peu de code pour avoir les idées claires :
    Code : 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
    22
    23
    24
    25
    26
    27
    void* NetworkManagement::acceptThread(void* args)
    {
        SOCKADDR_IN newSocketAdress;
        int size = sizeof(SOCKADDR);
        SOCKET newSocket = accept(m_sockServer,(SOCKADDR *)&newSocketAdress,&size);
     
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,nullptr);
        pthread_mutex_lock(&m_mutex);
     
        if(newSocket<0)
            std::cout<<"Impossible d'accepter une nouvelle requete"<<std::endl;
        else
        {
            for(unsigned int i=0;i<m_adressesEmission.size();i++)
                if(newSocketAdress.sin_addr.s_addr==inet_addr(m_adressesEmission[i].c_str()))
                {
                    m_socketsEmission[i].set(newSocket);
                    m_hasAdressEmissionBeenLinked[i] = true;
                    std::cout<<"Requete acceptee de la part de "<<m_socketsEmission[i].name()<<" a l'adresse "<<m_socketsEmission[i].adress()<<std::endl;
                }
        }
     
        pthread_mutex_unlock(&m_mutex);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,nullptr);
     
        return nullptr;
    }
    Supposons maintenant, vu que accept est ici une fonction bloquante, que je veuille mettre un délai d'acceptation au delà duquel le thread est annulé :
    Code : 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
    if(!pthread_create(&m_acceptThread,nullptr,&NetworkManagement::helper<void>,(void*)(&m_encapsulatedForAccept)))
    	cancel=true;
    else
    	std::cout<<"Impossible de creer le thread d'acceptation des connexions"<<std::endl;
     
    #ifdef WIN32
    Sleep(50);
    #elif defined(linux)
    msleep(50);
    #endif
     
    while(cancel&&!pthread_cancel(m_acceptThread))
    {
    	#ifdef WIN32
    	Sleep(10);
    	#elif defined(linux)
    	msleep(10);
    	#endif
    }
    cancel = false;
    J'avais pensé au départ que cela suffirait : tant que pthread_cancel n'échoue pas, c'est que le thread m_acceptThread est toujours là (cela peut par exemple être à cause du pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,nullptr)). Au final, on s'attend à ce que le thread finisse par être annulé.
    Sauf que malheureusement, ce n'est pas le cas. Je me suis renseigné à ce sujet, j'ai vu qu'il fallait soit utiliser la fonction pthread_testcancel, soit utiliser pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,nullptr) dans la fonction de callback.
    Cependant, j'ai également lu qu'utiliser pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,nullptr) ne devait se faire que lorsque le thread concerné ne gérait pas de mémoire (ça, ok), mais surtout ne gérait pas d'IO (ce qui, malheureusement, dans le cas du recv ou send, est le cas, et je me pose la question pour accept).

    Quelle serait la meilleure solution à adopter, pour interrompre une fonction de type accept avec pthread_cancel (ou autre, sans fermer la socket, et sans utiliser select/poll) ?

    Edit : Je viens de penser à une solution sûrement efficace mais particulièrement immonde j'imagine : utiliser std::thread de la manière suivante : on crée un pointeur sur std::thread, et on le delete quand on le désire, du coup cela force l'arrêt du thread . Comme je suis encore novice, pouvez-vous me dire en quoi cette méthode paraît horrible ?

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Je pense qu'il faille utiliser select. Cela me semble bancal votre truc. Sinon, je tenterai de tuer le accept avec un kill, ou pthread_kill, simplement. Mais j'avoue que j'ai eu un peu de mal à suivre votre histoire .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #ifdef WIN32
    Sleep(50);
    #elif defined(linux)
    msleep(50);
    #endif
    Je ferai une fonction "mySleep()" à votre place, qui encapsule ce genre de truc.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Disclaimer : Je ne suis pas certain de ce que je dis sur ce sujet...

    Le point positif, c'est que la fonction accept est un point de cancellation pour les threads posix, donc si tu essaye d'annuler un thread pendant qu'il est bloqué sur un accept, le thread va bien être arrêté.
    Le point négatif, c'est que ce n'est pas clair ce que "arrêter" veut dire En effet, posix étant principalement C (peut-être que le binding C++ est plus clair ?) il ne spécifie pas ce que ça donne pour les destructeurs sur la pile d'appel (RAII). Maintenant, certaines implémentations (linux, je ne sais pas sous windows) considèrent qu'arrêter signifie injecter une exception dans le thread. Ce qui fait sens (avec la question : que se passe-t-il si le thread catch l'exception ? C'est un désaccord là dessus qui fait que std::thread n'est pas annulable pour l'instant).


    http://udrepper.livejournal.com/21541.html donne plus de détails...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 274
    Points : 176
    Points
    176
    Par défaut
    Merci pour vos réponses,

    es-tu certain qu'accept est une fonction cancelable ? Parce que si c'était le cas, dans l'exemple,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while(cancel&&!pthread_cancel(m_acceptThread))
    {...
    }
    ne devrait pas boucler infiniment, or c'est le cas. Après, je ne sais pas du tout comment fonctionne pthread_cancel, si le thread est réellement détruit et non valide après cet appel lorsqu'il réussit (si ce n'était pas le cas, je comprends dans ce cas pourquoi la boucle est infinie, peut-être avez vous d'ailleurs des éclairages à ce propos).
    Je pense que je vais tenter un pthread_kill, ça devrait marcher, même si je ne suis pas très conscient des conséquences sur le programme et du thread détruit, ces questions demeurent floues dans mon esprit.

    qui fait que std::thread n'est pas annulable pour l'instant
    On ne peut donc pas annuler un std::thread, mais que se passe-t-il si le thread n'est pas terminé à la fin du main, si il n'y a pas de join ?

Discussions similaires

  1. Fonction bloquante attendant un signal
    Par Jorodan dans le forum GTK+ avec C & C++
    Réponses: 4
    Dernier message: 25/06/2007, 12h04
  2. [tcplistener]fonction bloquante et multithread
    Par ronan99999 dans le forum C#
    Réponses: 1
    Dernier message: 23/05/2007, 15h02
  3. Réponses: 3
    Dernier message: 10/01/2006, 14h01
  4. Réponses: 5
    Dernier message: 16/12/2005, 17h41
  5. [Threads] Sortir d'une fonction bloquante
    Par guejo dans le forum MFC
    Réponses: 19
    Dernier message: 17/08/2004, 14h12

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