Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
732 connectés 

  FORUM HardWare.fr
  Programmation
  C

  probleme thread linux (pthread)

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

probleme thread linux (pthread)

n°1915799
kus3000
Posté le 17-08-2009 à 15:20:27  profilanswer
 

Bonjour,
 
J'ai un problème de threads sous linux ubuntu 9.04.
Je code en C avec la bibliothèque <sys/socket.h>.
 
Avant de poster le code j'explique mon probleme :
Je dois réaliser un module de gestion de message (HTTP/TCP),  
et je me place entre un serveur S et un client C.
 
J'utilise LibCurl pour quelques étapes.
 
L'étape 1 consiste à réceptionner une requete HTTP de C
L'étape 2 consiste à la renvoyer à S.
S nous répond, on réceptionne la requette et on la relance a C.
 
Dans le principe, c'est simple. Mais l'on reçoit une cinquantaine de requete HTTP de C,
donc l'emploi des threads s'impose, et là c'est le drame (corruption de mémoire, etc.)
 
Il faut savoir que si je met les threads en mode JOIN, le programme marche !
Mais le but est bien entendu de lancer les 50 threads d'un coup, pas l'un a la suite de l'autre.
 
Voici la partie principale du code :
 

Code :
  1. if((socket_server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  2. {
  3.  printf("Socket creation error !\n" );
  4.  return EXIT_FAILURE;
  5. }
  6. // nous : on écoute sur le port HTTP (80) en local
  7. sockaddr_server.sin_family = AF_INET;
  8. sockaddr_server.sin_port = htons(80);
  9. sockaddr_server.sin_addr.s_addr = inet_addr("127.0.0.1" );
  10. server_len = sizeof(sockaddr_server);
  11. client_len = sizeof(sockaddr_client);
  12. if(setsockopt(socket_server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
  13.  printf("setsockopt" );
  14.  return EXIT_FAILURE;
  15. }
  16. if(bind(socket_server, (struct sockaddr*)&sockaddr_server, server_len) < 0)
  17. {
  18.  printf("Socket bind error !\n" );
  19.  return EXIT_FAILURE;
  20. }
  21. if(listen(socket_server, 10) != 0)
  22. {
  23.  printf("Socket listen error !\n" );
  24.  return EXIT_FAILURE;
  25. }
  26. int bEnd = 0;
  27. int iThreadNumber = 1;
  28.  pthread_attr_init(&attr);
  29. pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
  30. while(bEnd == 0)//boucle infinie pour le moment
  31. {
  32.  printf("[~]Waiting connection... \n" );
  33.  socket_client = accept(socket_server, (struct sockaddr*)&sockaddr_client, (socklen_t *)&client_len);
  34.  if(socket_client > 0)
  35.  {
  36.   printf("Recu une connection... socket %i\n",socket_client);
  37.   printf("IP du client : %s\n",inet_ntoa(sockaddr_client.sin_addr));
  38.   printf("Port du client : %i\n",ntohs(sockaddr_client.sin_port));
  39.   time(&date);
  40.   printf("[!]Established connection at %s\n", ctime(&date));
  41.   // reception du paquet HTTP
  42.   nbOctects = 0;
  43.   memset(requestHTTP,0,MAX_RECEPT);
  44.   if(   (nbOctects = read(socket_client, &requestHTTP, MAX_RECEPT))    < 0)
  45.   {
  46.    printf("Socket recv error !" );
  47.    return EXIT_FAILURE;
  48.   }
  49.   requestHTTP[nbOctects] = '\0';
  50.   printf("\n" );
  51.   printf("ETAPE 1 : Requete HTTP entière : (%d octects)\n", nbOctects);
  52.   //printf("%s\n", requestHTTP);  
  53.   /////////////////////////////////////////////////////////////////////////////////////////////////////////////     
  54.   // Gestion des threads :
  55.   ex = (struct infosThread *)malloc(sizeof(struct infosThread));
  56.   memset(ex,0,sizeof(struct infosThread));
  57.   if(ex!=NULL)
  58.   {
  59.    memcpy(&(ex->iSocketTCPClient),&socket_client, sizeof(socket_client));
  60.    memcpy(&(ex->iSizeRequetteHTTP),&nbOctects, sizeof(nbOctects));
  61.    memcpy(&(ex->iThreadNumber),&iThreadNumber, sizeof(iThreadNumber));
  62.    ex->cRequetteHTTP = (char *)malloc(sizeof(char) * nbOctects);
  63.    memcpy(ex->cRequetteHTTP,requestHTTP, nbOctects);
  64.    ex->cRequetteHTTP[nbOctects]='\0';
  65.   }else{
  66.    printf("probleme structure declaration\n" );
  67.   }
  68.   //lancement de la thread (etape 2 a finale)
  69.   printf("\n" );
  70.   printf(" --------------------------------------------- \n" );
  71.   printf(" LANCEMENT THREAD NUMERO %i sur socket %i\n",iThreadNumber,ex->iSocketTCPClient);
  72.   pthread_t thread;
  73.   usleep(10); // 10 ms
  74.   rc = pthread_create(&thread, &attr, print_message_function, (void *)ex);
  75.   if(rc != 0)
  76.   {
  77.    printf ("pthread_create error for thread\n" );
  78.    exit(0);
  79.   }
  80.   else
  81.   {
  82.    iThreadNumber++;//thread suivante
  83.   }
  84.   if(ex->cRequetteHTTP !=NULL){
  85.    free(ex->cRequetteHTTP);
  86.    ex->cRequetteHTTP= NULL;
  87.   }
  88.   if(ex!=NULL){
  89.    free(ex);
  90.    ex=NULL;
  91.   }
  92.  }
  93. }


 
 
Voici la fonction threadée :
 

Code :
  1. void * print_message_function( void *ptr )
  2. {
  3. char * requestHTTP = NULL;
  4. // récupération des données :
  5. int iSocketTCPClient = 0;
  6. int iSizeRequetteHTTP = 0;
  7. int iThreadNumber = 0;
  8. memcpy(&iSocketTCPClient,&(((struct infosThread *)(ptr))->iSocketTCPClient), sizeof(int));
  9. memcpy(&iSizeRequetteHTTP,&(((struct infosThread *)(ptr))->iSizeRequetteHTTP), sizeof(int));
  10. memcpy(&iThreadNumber,&(((struct infosThread *)(ptr))->iThreadNumber), sizeof(int));
  11. printf("iSocketTCPClient : %i\n",iSocketTCPClient);
  12. printf("iSizeRequetteHTTP : %i\n",iSizeRequetteHTTP);
  13. printf("iThreadNumber : %i\n",iThreadNumber);
  14. // PARFOIS iSocketTCPClient = 0 ! BUG !
  15. if(iSocketTCPClient > 0 && iSizeRequetteHTTP >0 && iThreadNumber >0)
  16. {
  17. requestHTTP = (char *)malloc(iSizeRequetteHTTP);// ici ça change la taille du ptr
  18. memset(requestHTTP,0,iSizeRequetteHTTP);
  19. memcpy(requestHTTP,((struct infosThread *)(ptr))->cRequetteHTTP,iSizeRequetteHTTP);
  20. requestHTTP[iSizeRequetteHTTP] = '\0';
  21. printf("taille  : %i     taille : %i    taille:%i\n",iSizeRequetteHTTP,strlen(requestHTTP),strlen(((struct infosThread *)(ptr))->cRequetteHTTP));
  22. printf("cRequetteHTTP :\n %s ",requestHTTP);
  23. /////////////////////////////////////////////////////////////////////////////////////
  24. //autres variables : (gestion des fichiers temporaires suivant les threads)
  25. char REQUEST_HTTP_THREAD[40]="";
  26. char RESPONSE_THREAD[40]="";
  27. sprintf(REQUEST_HTTP_THREAD,"thread_%i_1_requetteHTTP",iThreadNumber);
  28. sprintf(RESPONSE_THREAD,"thread_%i_2_reponse",iThreadNumber);
  29. /////////////////////
  30. // lancer le processus :
  31. printf("etape2\n" );
  32. /////////////////////////////////////////////////////////////////////////////////////////////////////////////     
  33. // ETAPE 2 : renvoyer la requete vers les serveurs
  34. CURL *curl = NULL;
  35. CURLcode res = 0;
  36. int sockfd = 0;
  37. size_t iolen = 0;
  38. curl = curl_easy_init();
  39. if(curl)
  40. {
  41.  // ici on met l'IP du server
  42.  curl_easy_setopt(curl, CURLOPT_URL, IP_SERVER);
  43.  // Do not do the transfer - only connect to host
  44.  curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
  45.  res = curl_easy_perform(curl);
  46.  if(CURLE_OK != res)
  47.  {
  48.   printf("Error: %s\n", strerror(res));
  49.   //return 1;
  50.  }
  51.  // Extract the socket from the curl handle - we'll need it for waiting
  52.  res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockfd);
  53.  //int flags = fcntl (sockfd, F_GETFL);
  54.  //fcntl (sockfd, F_SETFL, flags | O_NONBLOCK);  
  55.  if(res != CURLE_OK)
  56.  {
  57.   printf("Error: %s\n", strerror(res));
  58.   //return 1;
  59.  }
  60.  // wait for the socket to become ready for sending
  61.  if(!wait_on_socket(sockfd, 0, 10000L))
  62.  {
  63.   printf("Error: timeout.\n" );
  64.   //return 1;
  65.  }
  66.  printf("Sending request (thread(%i)) from TV to Server\n",iThreadNumber);
  67.  // sauvegarde de la requete dans un fichier :
  68.  FILE * pRequestHTTP = fopen(REQUEST_HTTP_THREAD, "wb" );
  69.  if(pRequestHTTP)
  70.  {
  71.   fwrite(requestHTTP,1,iSizeRequetteHTTP,pRequestHTTP);
  72.   fclose(pRequestHTTP);
  73.  }//  
  74.  // Send the requestHTTP. Real applications should check the iolen to see if all the request has been sent
  75.  res = curl_easy_send(curl, requestHTTP, strlen(requestHTTP), &iolen);
  76.  if(res != CURLE_OK)
  77.  {
  78.   printf("Error: %s\n", strerror(res));
  79.   exit(1);
  80.   //return 1;
  81.  }
  82.  printf("Reading response (thread(%i)) from Server.\n",iThreadNumber);
  83. printf("etape3\n" );
  84.  ////////////////////////////////////////////////////  
  85.  // ETAPE 3 : récupérer la réponse du serveur
  86.  int iPart = 0;
  87.  FILE * pReponse = fopen (RESPONSE_THREAD,"wb" );
  88.  char buf[MAX_RECEPT]="";
  89.  memset(buf,0,MAX_RECEPT);
  90.  if(pReponse)
  91.  {
  92.   for(;;)
  93.   {
  94.    wait_on_socket(sockfd, 1, 500L);
  95.    res = curl_easy_recv(curl, buf, MAX_RECEPT, &iolen);
  96.    fwrite(buf,1,iolen,pReponse);// en binaire !!!!!
  97.    memset(buf,0,MAX_RECEPT);
  98.    if(res != CURLE_OK){ break; }
  99.    iPart++;
  100.   }
  101.   ////////////////////////////////////////////////////
  102.   fclose (pReponse);
  103.  }
  104.  else{
  105.   printf("impossible d'ouvrir %s\n",RESPONSE_THREAD);
  106.  }
  107.  printf("Reading response (thread(%i)) from Server DONE !.\n",iThreadNumber);
  108.  curl_easy_cleanup(curl);
  109. }
  110. /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. printf("etape Finale\n" );
  112. /////////////////////////////////////////////////////////////////////////////////////////////////////////////     
  113. // ETAPE FINALE
  114. char * cBody = NULL;
  115. int nbOctects = 0;
  116. FILE * pBodyfileRead = fopen (RESPONSE_THREAD,"rb" );
  117. // obtain file size:
  118. fseek (pBodyfileRead , 0 , SEEK_END);
  119. long lSize = ftell (pBodyfileRead);
  120. rewind (pBodyfileRead);
  121. // allocate memory to contain the whole file:
  122. cBody= (char*) malloc (sizeof(char)*lSize);
  123. memset(cBody,0,sizeof(char)*lSize);
  124. if (cBody== NULL) {fputs ("Memory error",stderr); exit (2);}
  125. // copy the file into the buffer:
  126. int result = fread (cBody,1,lSize,pBodyfileRead);
  127. cBody[lSize] = '\0';
  128. if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
  129. //pthread_mutex_lock (&my_mutex);
  130. // cBodycontiennent les informations a renvoyer a la box
  131. // on renvoie a la netgem box tv du départ :
  132. //int flags = fcntl (iSocketTCPClient, F_GETFL);
  133. //fcntl (iSocketTCPClient, F_SETFL, flags | O_NONBLOCK);  
  134. if(  (nbOctects = write(iSocketTCPClient, cBody, lSize)) < 0)
  135. {
  136.  printf("Socket send error !" );
  137.  return (void *)EXIT_FAILURE;
  138. }
  139. else
  140. {
  141.  printf("etape finale (thread(%i)): %i envoyés\n", iThreadNumber, nbOctects);
  142. /*  
  143.  struct timeval to;  
  144.  fd_set myset;
  145.  
  146.  to.tv_sec = 0;
  147.  to.tv_usec =0; //microseconde
  148.  
  149.  FD_ZERO(&myset);
  150.  FD_SET(iSocketTCPClient,&myset);
  151.  if(select(iSocketTCPClient+1,&myset,NULL,&myset,&to) == 1){
  152.   printf("EVENEMENT !\n" );
  153.   return (void *)-1;
  154.  }
  155. */
  156. }
  157. fclose(pBodyfileRead);
  158. if(cBody!=NULL){
  159.  free(cBody);
  160.  cBody=NULL;
  161. }
  162. /////////////////////////////////////////
  163. /////////////////////////////////////////////////////////////////////////////////////////////////////////////     
  164. // Nettoyage de sockets et des pointeurs :
  165. remove(REQUEST_HTTP_THREAD);
  166. remove(RESPONSE_THREAD);
  167. }
  168. printf("Close sockets (thread(%i))\n",iThreadNumber);
  169. int iCheckSocketClosedClient = close(iSocketTCPClient);
  170. iSocketTCPClient=-1;
  171. printf("Check state of sockets (0 is OK) : Client : %i\n", iCheckSocketClosedClient);
  172. if(requestHTTP!=NULL){
  173.  free(requestHTTP);
  174.  requestHTTP=NULL;
  175. }
  176. printf(" FIN THREAD NUMERO %i\n",iThreadNumber);
  177. printf(" --------------------------------------------- \n" );
  178. printf("\n" );
  179. pthread_exit ((void *)0);
  180. }

mood
Publicité
Posté le 17-08-2009 à 15:20:27  profilanswer
 

n°1915803
ptitchep
Posté le 17-08-2009 à 15:23:10  profilanswer
 

Quel est le problème?


---------------
deluser --remove-home ptitchep
n°1915807
kus3000
Posté le 17-08-2009 à 15:27:26  profilanswer
 

J'ai ce genre d'erreur :
*** glibc detected *** ./main: corrupted double-linked list: 0x09fe3b58 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb7dcb07f]
/lib/tls/i686/cmov/libc.so.6[0xb7dccb8d]
/lib/tls/i686/cmov/libc.so.6(__libc_calloc+0xef)[0xb7dce6ef]
/usr/local/lib/libcurl.so.4(Curl_open+0x36)[0xb7ef8226]
/usr/local/lib/libcurl.so.4(curl_easy_init+0x37)[0xb7f06697]
./main[0x8049aec]
/lib/tls/i686/cmov/libpthread.so.0[0xb7ec44ff]
/lib/tls/i686/cmov/libc.so.6(clone+0x5e)[0xb7e3f49e]
 
etc............
 
Parfois j'ai ça, parfois le programme se bloque (comme s'il ne recevait plus de connection...) dur dur

n°1915827
ptitchep
Posté le 17-08-2009 à 15:56:43  profilanswer
 

Alors ce n'est sans doute pas la solution, mais je dirais que  

Code :
  1. ex = (struct infosThread *)malloc(sizeof(struct infosThread));
  2. rc = pthread_create(&thread, &attr, print_message_function, (void *)ex);
  3. if(ex->cRequetteHTTP !=NULL){
  4.    free(ex->cRequetteHTTP);
  5.    ex->cRequetteHTTP= NULL;
  6.   }
  7.   if(ex!=NULL){
  8.    free(ex);
  9.    ex=NULL;
  10.   }


c'est moyen parce que rien n'indique que le thread a eu le temps de se servir de ton pointeur avant que tu ne libères la mémoire. Tu devrais libérer dans le thread je pense.


---------------
deluser --remove-home ptitchep
n°1915847
kus3000
Posté le 17-08-2009 à 16:11:49  profilanswer
 

je vais essayer cette solution pourquoi pas !
 
je ne savais pas qu'il est possible de libérer dans le thread l"élément passé en paramètre

n°1915855
ptitchep
Posté le 17-08-2009 à 16:19:17  profilanswer
 

Ton élément n'est qu'un pointeur, pas la zone mémoire en question.
Essaie:

Code :
  1. int *i=malloc (4*sizeof(int));
  2. int *z=i;
  3. free(z);


Tu verras qu'il n'y a pas de problème. z peut aussi être défini dans une autre fonction. Par contre il ne faut pas oublier de libérer la mémoire et de ne pas le faire deux fois.


Message édité par ptitchep le 17-08-2009 à 16:23:57

---------------
deluser --remove-home ptitchep
n°1915862
kus3000
Posté le 17-08-2009 à 16:23:20  profilanswer
 

bon ça a l'air de marcher un chouillia mieux (j'ai enlever le usleep aussi)
je traite bien une quinzaine de threads et le glibc error arrive d'un coup

n°1915869
kus3000
Posté le 17-08-2009 à 16:26:31  profilanswer
 

j'ai mis :
 
 // libération de la structure :
 if(((struct infosThread *)(ptr))->cRequetteHTTP !=NULL){
  free(((struct infosThread *)(ptr))->cRequetteHTTP);
  ((struct infosThread *)(ptr))->cRequetteHTTP= NULL;
 }
 
 if(ptr!=NULL){
  free(ptr);
  ptr = NULL;
 }
 
a la fin de la fonction threadé

n°1915873
kus3000
Posté le 17-08-2009 à 16:30:57  profilanswer
 

je ne pense pas que ce soit ça l'erreur, car si je commente les free(structure) que ce soit dans la fonction thréadé ou dans la boucle, ça plante de la même manière !

n°1915876
ptitchep
Posté le 17-08-2009 à 16:33:22  profilanswer
 

Utilise un debugger pour trouver la ligne qui plante. Vu d'ici avec juste un bout de code et une erreur ce n'est pas facile. Surtout que honnêtement, je n'ai pas tout lu XD. Je pense que si tu arrives à trouver l'instruction qui fait tout tomber, tu pourrais identifier le problème.

 

Ca ne plantait pas parce que tu avais de la chance et que le thread copiait les infos avant qu'elles ne soient détruites.
Si ptr est NULL, tu auras une segmentation fault sur  if(((struct infosThread *)(ptr))->cRequetteHTTP !=NULL). Vérifie d'abord ptr avant ptr->cRequetteHTTP. Par contre les free sont dans le bon ordre.

 

(Je l'avais dit que ça n'était sûrement pas le problème: tu aurais eu seg fault comme message d'erreur)

 

Au fait la pile d'appels de ton message d'erreur parle de curl. Tu appelles peut-être une fonction de cette bibliothèque en lui donnant une variable avec du caca dedans...


Message édité par ptitchep le 17-08-2009 à 16:41:51

---------------
deluser --remove-home ptitchep
mood
Publicité
Posté le 17-08-2009 à 16:33:22  profilanswer
 

n°1915894
kus3000
Posté le 17-08-2009 à 16:47:36  profilanswer
 

en utilsant gdb il mécrit la même chose que au dessus

n°1915923
tpierron
Posté le 17-08-2009 à 17:38:33  profilanswer
 

Oué, débugguage de programme multi-threadé en C, des heures de plaisir en vue :love:  
 
Le genre d'erreur que tu obtiens, ça pu à plein nez le buffer overflow, erreur assez difficile à corriger.
 
Déjà, dans ce pavé, il y a une ligne qui devrait t'arracher les yeux :

Code :
  1. requestHTTP = (char *)malloc(iSizeRequetteHTTP);// ici ça change la taille du ptr
  2. memset(requestHTTP,0,iSizeRequetteHTTP);
  3. memcpy(requestHTTP,((struct infosThread *)(ptr))->cRequetteHTTP,iSizeRequetteHTTP);
  4. requestHTTP[iSizeRequetteHTTP] = '\0';


 
Ce qui n'est pas gagné, car si tu fais ce genre d'erreur sur des trucs aussi simple, tu vas en chier pour la suite.


Message édité par tpierron le 17-08-2009 à 17:39:03
n°1915925
kus3000
Posté le 17-08-2009 à 17:45:31  profilanswer
 

je ne comprend pas, quelle est l"erreur mon ami ? je ne suis sans doute pas un pro comme toi :)

n°1915930
tpierron
Posté le 17-08-2009 à 17:53:18  profilanswer
 

Hmm, pas besoin d'être un pro pour comprendre ton erreur. Pour la débusquer au milieu du tas, il faut de l'expérience, certes. Mais maintenant que que je te l'ai montrée, tu dois comprendre ce qui ne vas pas, parce que c'est la base du C. Si tu ne veux pas faire cet effort, j'ai sincèrement peur pour la suite de ton projet.
 
Surtout que j'ai juste survolé ton code, rien ne dit que c'est l'unique erreur qu'il puisse y avoir.

n°1915931
kus3000
Posté le 17-08-2009 à 18:01:45  profilanswer
 

tu me serai d'une grande aide si tu pouvais m'aider.
ça fait vraiment un moment que je bloque !
j'ai beau cherché je ne comprend pas mon erreur...

n°1915938
kus3000
Posté le 17-08-2009 à 18:14:48  profilanswer
 

j'ai fait :
 
if(iSizeRequetteHTTP == strlen(((struct infosThread *)(ptr))->cRequetteHTTP)){
  strcpy(requestHTTP,((struct infosThread *)(ptr))->cRequetteHTTP);
}else{
  printf("probleme taille !!!!\n" );
}
 
et il arrive quon n'est pas la même taille... tu métonnes que ça narrive pas a bien copié !
mais alors pourquoi en faisant  
iSizeRequetteHTTP = ((struct infosThread *)(ptr))->iSizeRequetteHTTP;
2 lignes après ils sont différents !! ça mépate là


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  probleme thread linux (pthread)

 

Sujets relatifs
Problème avec jQueryproblème de recuperation de la date
Linux / Cross CompilingProblème retour à la ligne données mysql
Probleme de DLL ? "Automation type not supported in Visual Basic"Problème de connection Mysql en local, avec Easyphp ou Wampserver [OK]
[CWebControl2]Probleme avec Navigate[C++] Cherche lib + howto pour utiliser le pilote wifi (linux)
Debutant VB: un probleme de ligne a copier!!!problème de recuperation des données
Plus de sujets relatifs à : probleme thread linux (pthread)


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR