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 :
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
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; }
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é.
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;
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 ?
Partager