Erreur flagrante? Serveur (sockets + threads)

Erreur flagrante? Serveur (sockets + threads) - C - Programmation

Marsh Posté le 08-11-2005 à 23:38:13    

Bien le bonjour a tous! :hello:  
 
Voila j'ai cette annee un projet tutore a faire(2e annee de dut info gestion).Pour cela je suis en train de developper un serveur multiclient en C.J'utilise donc les threads et les sockets, et je travaille sous linux (y'aura ptet du windows dans l'affaire plus tard mais c'est optionnel si le temps le permet)
Ne connaissant pas grand chose a la programmation reseau, j'ai cherche sur le net des tuto, des exemples et tout ce qui pouvait m'aider et grace a tout ca et pas mal de temps j'en ai sorti quelquechose qui devrait etre potable (non non c'est pas portable  :lol: ) :D  
 Seulement avant de continuer plus loin, et au vu de ma tres petite experience dans la prog reseau je souhaiterai savoir si dans le code de mon serveur, il vous apparait des erreurs grossieres, des failles assez moches ou memes des fuites de memoires.
Enfin je voudrais avoir au final un code si possible le plus propre possible donc je demande un peu d'aide exterieure
 

Code :
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netdb.h>
  8. #include <unistd.h>
  9. #include <pthread.h>
  10. #ifndef  LONGUEUR_MAX
  11. #define  LONGUEUR_MAX 256
  12. #define  MAX_CLIENTS 10
  13. #define         NB_FILE_CLIENTS 5
  14. #define   PSEUDO               "Bienvenue...\nEntrez votre pseudo : "
  15. /*erreurs*/
  16. #define  ERR_OPEN_SOCK "Erreur d'ouverture de la socket!\n"
  17. #define  ERR_BIND "Erreur de bind!\n"
  18. #define  ERR_LISTEN "Erreur de listen!\n"
  19. #define  ERR_ALLOCATE_MEM_CLIENT "Erreur d'allocation memoire pour le client!\n"
  20. #define  ERR_PSEUDO "Erreur de pseudo! Celui choisi est deja en cours d'utlisation!\n"
  21. #define  ERR_WRITE "Erreur d'ecriture!\n"
  22. #define  ERR_ALLOCATE_MEM_PSEUDO "Erreur lors de l'allocation memoire pour le pseudo!\n"
  23. #define  ERR_RESEAU "Erreur de reseau!\n"
  24. #define  ERR_ACCEPT "Erreur d'acceptation d'un client\n"
  25. #endif
  26. #define PORT 1798
  27. struct s_client{
  28. pthread_t id;
  29. int socket;
  30. char * pseudo;
  31. };
  32. typedef struct s_client client;
  33. typedef struct sockaddr_in struct_socket;
  34. client tab_clients[MAX_CLIENTS];
  35. char nom_serveur[LONGUEUR_MAX];
  36. int case_libre=0;
  37. int nb_clients;
  38. /**************************************************************/
  39. /*   Creation serveur        */
  40. /**************************************************************/
  41. int creation_serveur(int port){
  42. /*variables utiles a la creation du serveur*/
  43. int sock;
  44. struct_socket adresse_socket;
  45. /*initialisation du nom du serveur*/
  46. gethostname(nom_serveur,sizeof(nom_serveur));
  47. if ((sock=socket(PF_INET,SOCK_STREAM,0))<0){
  48.  printf (ERR_OPEN_SOCK);
  49.  exit(-1);
  50. }
  51. /*initialisation du serveur*/
  52. memset(&adresse_socket,0,sizeof(struct sockaddr_in));
  53. adresse_socket.sin_family=AF_INET;
  54. adresse_socket.sin_port=htons(port); // htons convertit un entier court en entier "reseau"
  55. adresse_socket.sin_addr.s_addr=htonl(INADDR_ANY); // htonl : de meme que htons mais pour un entier long  INADDR_ANY=0 -> designe l'adresse du poste sur lequel est lance le programme  
  56. /*affectation d'un nom a la socket*/
  57. if (bind (sock,(struct sockaddr *)&adresse_socket,sizeof(struct sockaddr_in))<0){
  58.  perror (ERR_BIND);
  59.  exit(-1);
  60. }
  61. /*"initialisation" des "options" d'ecoute de la socket*/
  62. if (listen(sock,NB_FILE_CLIENTS)<0){
  63.  perror (ERR_LISTEN);
  64.  exit(-1);
  65. }
  66. return sock;
  67. }
  68. /**************************************************************/
  69. /*  Envoi de message a un seul client             */
  70. /**************************************************************/
  71. int envoi_message(int sock, char * message){
  72. if ((write(sock,message,strlen(message)))==-1){
  73.    perror(ERR_WRITE);
  74.    return 1;
  75. }
  76. return 0;
  77. }
  78. /**************************************************************/
  79. /*   Envoi de message a tous les clients sauf celui specifie  */
  80. /**************************************************************/
  81. int envoi_limite(char * message,int sock){
  82. int i;
  83. for (i=0;i<case_libre;i++){
  84.  if(tab_clients[i].socket != sock){
  85.   envoi_message(tab_clients[i].socket,message);
  86.  }
  87. }
  88. return 0;
  89. }
  90. /**************************************************************/
  91. /* Envoi d'un message a tous les clients du serveur      */
  92. /**************************************************************/
  93. int envoi_general(char * message){
  94. int i;
  95. for (i=0;i<case_libre;i++){
  96.  envoi_message(tab_clients[i].socket,message);
  97. }
  98. return 0;
  99. }
  100. /**************************************************************/
  101. /*  Depart d'un client         */
  102. /**************************************************************/
  103. void client_quit(client * client_courant,char * raison){
  104. int i,j;
  105. char buf[8192+1];
  106. if ((strcmp(raison,'\0'))>0){
  107.  snprintf(buf,8192,"%s part vers d'autres cieux...(%s)\n",client_courant->pseudo,raison);
  108. }
  109. else {
  110.  snprintf(buf,8192,"%s part vers d'autres cieux...(%s)\n",client_courant->pseudo,raison);
  111. }
  112. envoi_limite(buf,client_courant->socket);
  113. /*recherche du client dans tab_clients*/
  114. for (i=0;(tab_clients[i].socket != client_courant->socket);i++);
  115. /*liberation des ressources du client*/
  116. close(client_courant->socket);
  117. free(client_courant->pseudo);
  118. free(client_courant);
  119. /*reorganisation de tab_clients*/
  120. for (j=i+1;j<case_libre;j++){
  121.  tab_clients[j-1]=tab_clients[j];
  122. }
  123. case_libre--;
  124. nb_clients--;
  125. }
  126. /**************************************************************/
  127. /*      Acceptation d'un client par le serveur           */
  128. /**************************************************************/
  129. int client_accepte(int socket_serveur){
  130.   int socket_client;
  131.   if((socket_client = accept(socket_serveur,NULL,0)) < 0)
  132.     {
  133.       if(errno == EINTR)
  134. {
  135.   shutdown(socket_serveur,SHUT_RDWR);
  136.   close(socket_serveur);
  137.   nb_clients--;
  138.   return -1;
  139. }
  140.       else
  141. {
  142.   perror(ERR_ACCEPT);
  143.   exit(-1);
  144. }
  145.     }
  146.   fcntl(socket_client,F_SETFD,1);
  147.   return socket_client;
  148. }
  149. /**************************************************************/
  150. /*      Interaction avec le client : thread              */
  151. /**************************************************************/
  152. void * thread_client(void *args){
  153. char pseudo[255];
  154. char message_emis[8192+1];
  155. char message_recu[4096+1];
  156. int case_libre=0;
  157. int len,i;
  158. int sock=*((int *)args);
  159. client *client_courant=NULL;
  160. if ((client_courant=malloc (sizeof(struct s_client)))==NULL){
  161.  perror (ERR_ALLOCATE_MEM_CLIENT);
  162.  close (sock);
  163.  nb_clients--;
  164.  pthread_exit(NULL);
  165. }
  166. envoi_message(sock,PSEUDO);
  167.              len = read(sock,message_recu,4096);
  168.              if(len <= 0) {
  169.  printf("\nErreur\n" );
  170.  close(sock);
  171.  free(me);
  172.  client_courant = NULL;
  173.  nb_clients--;
  174.  pthread_exit(NULL);
  175. }
  176. /*recuperation du pseudo du client courant*/
  177. for (i=0;(pseudo[i]!='\0')&&(pseudo[i]!='\n');i++);  //on va a la fin du pseudo
  178. pseudo[i]='\0'; // on met un \0 pour le terminer proprement
  179. for (i=0;i<case_libre;i++){
  180.  if (strcmp(pseudo,tab_clients[i].pseudo)==0){ // si strcmp==0 alors les chaines sont identiques
  181.   if ((write(sock,ERR_PSEUDO,strlen(ERR_PSEUDO)))==-1){
  182.    perror(ERR_WRITE);
  183.   }
  184.   close (sock); //fermeture de la socket du client courant
  185.   free(client_courant); //liberation de la memoire allouee pour le client courant
  186.   nb_clients--;
  187.   pthread_exit(NULL);
  188.  }
  189. }
  190. /*initialisation de la structure du client courant*/
  191. if(client_courant->pseudo=malloc(sizeof(pseudo))==NULL){
  192.  perror (ERR_ALLOCATE_MEM_PSEUDO);
  193.  nb_clients--;
  194.  pthread_exit(NULL);
  195. }
  196. client_courant->id=pthread_self();
  197. client_courant->socket=sock;
  198. strcpy(client_courant->pseudo,pseudo);
  199. /*placement du client dans le tab_client a la premiere "case libre"*/
  200. tab_clients[case_libre]=*client_courant;
  201. case_libre++; //le prochaine case libre du tableau est un rang plus loin
  202. snprintf(message_emis,8192,"Nouveau Client : %s\n",client_courant->pseudo);
  203. message_emis[8192]='\0';
  204. if ((write(sock,message_emis,strlen(message_emis)))==-1){
  205.    perror(ERR_WRITE);
  206. }
  207. while (1){
  208.  len=read(sock,message_recu,8192); //read retourne le nombre d'octets lus, -1 en cas d'echec, 0 si rien ou en fin de fichier
  209.  if (len<=0){ //s'il y a erreur de lecture ou fin du message
  210.   client_quit(client_courant,ERR_RESEAU);
  211.   pthread_exit(NULL);
  212.  }
  213.  message_recu[len]='\0';
  214.  snprintf(message_emis,8192,"%s : %s\n",client_courant->pseudo,message_recu);
  215.  message_emis[8192]='\0';
  216.  envoi_general(message_emis);
  217. }
  218. return NULL;
  219. }
  220. /**************************************************************/
  221. /*      Fonction principale : lancement du serveur       */
  222. /**************************************************************/
  223. int main(int argc, char **argv)
  224. {
  225. int socket_serveur,socket_client;
  226. pthread_t id;
  227. socket_serveur = create_server(PORT);
  228. while(1)
  229. {
  230.  if ((socket_client = client_accepte(socket_serveur))==-1){
  231.   perror(ERR_ACCEPT);
  232.   exit(-1);
  233.  }
  234.  if(nb_clients < MAX_CLIENTS)
  235.  {
  236.   pthread_create(&id,NULL,thread_client,(void *)&socket_client);
  237.   nb_clients++;
  238.   printf("Nouveau client! Il y a actuellement %d clients sur le serveur\n",nb_clients);
  239.  }
  240.  else close(socket_client);
  241. }
  242. return 0;
  243. }


 
J'avoue c'est un peu long alors je remercie d'avance ceux qui auront la patience de tout lire et de m'aider  :)  
Merci


Message édité par gocho le 10-11-2005 à 00:14:39
Reply

Marsh Posté le 08-11-2005 à 23:38:13   

Reply

Marsh Posté le 09-11-2005 à 23:45:01    

y'as pas de fautes ? :)

Reply

Marsh Posté le 09-11-2005 à 23:47:42    

exit, c'est moche
 

Code :
  1. if ((write(sock,message,strlen(message)))==-1)


 
a mon avis ton test est pas bon, tu dois vérifier que write te retourne bien le meme nombre d'octet que tu lui a demandé d'ecrire

Message cité 1 fois
Message édité par chrisbk le 09-11-2005 à 23:48:39
Reply

Marsh Posté le 09-11-2005 à 23:51:33    

Code :
  1. if ((strcmp(raison,'\0'))>0){


 
tordu
 
 

Code :
  1. if (strlen(raison)>0)


 

Code :
  1. for (i=0;(pseudo[i]!='\0')&&(pseudo[i]!='\n');i++);


 
pour ce genre de chose, je trouve while plus logique est plus lisible
 
 
sinon spa trop mal, par contre je suis vraiment pas allé dans le detail

Reply

Marsh Posté le 10-11-2005 à 00:02:55    

chrisbk a écrit :

exit, c'est moche
 

Code :
  1. if ((write(sock,message,strlen(message)))==-1)


 
a mon avis ton test est pas bon, tu dois vérifier que write te retourne bien le meme nombre d'octet que tu lui a demandé d'ecrire


 
exit C'est juste moche ou c'est deprecated (j'aime bien ce mot  :D )? return c'est mieux?
 
 
pour le write j'ai teste si ca avait pas echoue.Ce serait mieux si je faisais ca?

Code :
  1. if ((write(sock,message,strlen(message)))!=(strlen(message))


 
 

Citation :

Code :
  1. for (i=0;(pseudo[i]!='\0')&&(pseudo[i]!='\n');i++);


 
pour ce genre de chose, je trouve while plus logique est plus lisible


voui c'est sur...vais changer ca.
 
 

Citation :

sinon spa trop mal, par contre je suis vraiment pas allé dans le detail


merci.si en superficiel deja ca le fait....

Reply

Marsh Posté le 10-11-2005 à 00:06:54    

gocho a écrit :

exit C'est juste moche ou c'est deprecated (j'aime bien ce mot  :D )? return c'est mieux?


 
juste moche, il vaut mieux faire remonter l'erreur aussi haut que possible, des fois qu'il y ait des liberations de ressources a faire

Citation :


 
pour le write j'ai teste si ca avait pas echoue.Ce serait mieux si je faisais ca?

Code :
  1. if ((write(sock,message,strlen(message)))!=(strlen(message))



 
ca te fais deux strlen, et trois appels de fonction sur une meme ligne, ca devient guere lisible
 

Citation :

size_t truc = strlen(message);


et zou avec truc
 

gocho a écrit :


merci.si en superficiel deja ca le fait....


 
bin ptet je traine trop ici, a force de voir des horreurs accablante on perds la faculté a chercher la ptite bete [:moule_bite]

Reply

Marsh Posté le 10-11-2005 à 00:08:27    

Code :
  1. else close(sock);


 
y sort d'ou, ce sock ?
 
(bon sinon les vars globales, ca aussi c'est moche)

Reply

Marsh Posté le 10-11-2005 à 00:10:08    

heuh mais ca compile et ca se lance, ton truc ? [:le kneu]

Reply

Marsh Posté le 10-11-2005 à 00:16:41    

euh j'ai po trop compris le "zou avec truc " ^^
le sock c'est quand j'ai renomme mes variables, j'ai oublie celle la (et je m'etonnais de me taper un segfault quand je terminais....je comprends un peu maintenant :p
Sinon ouais ca se compile et ca se lance (enfin aujourd'hui parce que j'ai fait quelques modifs dessus toute a l'heure et j'ai pas eu le temps de les reporter ici )

Reply

Marsh Posté le 10-11-2005 à 00:17:18    

bin des "sock" t'en a plein ton programme, donc je m'etonne un peu que ca compile [:el g]

Reply

Marsh Posté le 10-11-2005 à 00:17:18   

Reply

Marsh Posté le 10-11-2005 à 00:18:06    

et pour les globales vaut mieux que je les declare dans le main et que je les passe en param de chaque fonction ou j'en ai besoin?

Reply

Marsh Posté le 10-11-2005 à 00:19:26    

pour le sock ca depend des fonctions en fait, il me semble que c'etait le seul.
Dans les autres c'est normal (enfin va falloir que je repasse ca au crible : :D : )

Reply

Marsh Posté le 10-11-2005 à 00:19:41    

bin vu leur tronche, deja je dirais qu'elles iraient bien dans une structure, vu qu'elles servent a decrire une seule et meme chose (un serveur et ses clients), ca te limitera le paquet
 
apres comme t'es en environnement multithread, il faut que tu geres avec attention l'utilisations de ce genre de variable partagée entre plusieurs thread. (utilisation de synchronisation)
 

Reply

Marsh Posté le 10-11-2005 à 00:21:56    

ah...j'pensais bien que ca viendrait la.
Comme j'ai pas encore vraiment bien capte tout ca :  
La synchro c'est comment on la fait? c'est juste empecher deux threads d'acceder a la meme variable en meme temps avec les mutex c'est ca? (j'ai jete un coup d'oeil mais pas encore eu le temps de m'atteler a la tâche)

Reply

Marsh Posté le 10-11-2005 à 00:24:44    

et pour la structure un truc du genre  :  

Code :
  1. struct _serveur{
  2. char nom_serveur[LONGUEUR_MAX];
  3. int nb_clients;
  4. int case_libre;
  5. client tab_clients[MAX_CLIENTS];
  6. };
  7. typedef struct _serveur serveur;

 
ca le fait?

Message cité 1 fois
Message édité par gocho le 10-11-2005 à 00:25:00
Reply

Marsh Posté le 10-11-2005 à 00:24:52    

gocho a écrit :


La synchro c'est comment on la fait? c'est juste empecher deux threads d'acceder a la meme variable en meme temps avec les mutex c'est ca? (j'ai jete un coup d'oeil mais pas encore eu le temps de m'atteler a la tâche)


 
ouais, par exemple.
 
Si on prends une de tes boucles
 

Code :
  1. for (i=0;i<case_libre;i++){


 
la c'est dangeureux car tu te bases sur une borne qui peut potentiellement varier. Imagine la cas le plus moche,  
 
 
thread 1 : compare i (2) avec case_libre (3)
thread 1: entre dans la boucle (condition valide)
 
thread 2 : decremente case_libre, libere la vieille socket situé en client[2]
 
thread 1 : essaye d'ecrire sur client[2]
 
Blam
 
 
 
 
 
 

Reply

Marsh Posté le 10-11-2005 à 00:25:53    

gocho a écrit :

et pour la structure un truc du genre  :  

Code :
  1. struct _serveur{
  2. char nom_serveur[LONGUEUR_MAX];
  3. int nb_clients;
  4. int case_libre;
  5. client tab_clients[MAX_CLIENTS];
  6. };
  7. typedef struct _serveur serveur;

 
ca le fait?


 
ouais, un peu bourrin mais disons que tu debutes alors oui :d
 
par contre tu peux t'eviter des lignes
 

Code :
  1. typedef struct _serveur{
  2. client tab_clients[MAX_CLIENTS];
  3. char nom_serveur[LONGUEUR_MAX];
  4. int nb_clients;
  5. int case_libre;
  6. }serveur;


Reply

Marsh Posté le 10-11-2005 à 00:26:11    

ah j'avoue ca va faire un gros bouzin si ca se passe ca...hop poubelle le programme :p

Reply

Marsh Posté le 10-11-2005 à 00:27:19    

gocho a écrit :

ah j'avoue ca va faire un gros bouzin si ca se passe ca...hop poubelle le programme :p


 
vala. Donc faut proteger au mutex. Ca allourdi le code donc essaye de faire ca proprement
 
(le multithread c'est clairement pas chose facile)

Reply

Marsh Posté le 10-11-2005 à 00:28:31    

oue j'aime bien voir toutes les lignes, l'optimisation des lignes c'est pas mon truc :D
 
Sinon pourquoi bourrin? qu'est ce qu'il y aurait de moins bourrin?(ve apprendre moi :))

Reply

Marsh Posté le 10-11-2005 à 00:29:26    

gocho a écrit :


Sinon pourquoi bourrin? qu'est ce qu'il y aurait de moins bourrin?(ve apprendre moi :))


 
Bin ce qu'il y a de bourrin c'est le codage direct du nombre de client max et ce genre de truc. Ca fait des gros tableaux dans une structure, c'est pas forcement élegant. une alloc dynamique serait de bon aloy, quoi

Message cité 1 fois
Message édité par chrisbk le 10-11-2005 à 00:29:46
Reply

Marsh Posté le 10-11-2005 à 00:30:23    

ben d'apres ce que j'ai vu sur les mutex ca donnerai un truc dans le style :  
 

Code :
  1. int main(int argc, char*argv[]){
  2. //je declare le mutex
  3. //je mets toutes mes conneries
  4. //je block  
  5. //je touche aux variables sensibles  
  6. //je debloke
  7. }

 
Is it right?

Reply

Marsh Posté le 10-11-2005 à 00:31:15    

chrisbk a écrit :

Bin ce qu'il y a de bourrin c'est le codage direct du nombre de client max et ce genre de truc. Ca fait des gros tableaux dans une structure, c'est pas forcement élegant. une alloc dynamique serait de bon aloy, quoi


 
un p'ti coup de malloc donc...j'vais commencer a bien le gerer celui la a la fin  :lol:
 
edit : attends attends...si je declare mon tableau de client avec un malloc.
il est donc NULL au debut.
Mais si je le remplis, ca veut dire realloc a chaque nouveau client/depart de client ?c'est bien ca ( :cry:  inside)?

Message cité 1 fois
Message édité par gocho le 10-11-2005 à 00:32:50
Reply

Marsh Posté le 10-11-2005 à 00:33:34    

en gros, mais pas que dans le main hein ? tes fonctions envoi_limite et envoi_general en profiterait bien aussi, par exemple.
 
Y'a de la bonne base, mais y'aurait pas mal de chose a faire sur ton code pour le rendre plus chouette et solide, seulement la chui un peu claqué [:pingouino] Essaye de voir si certaines parties peuvent etre redécoupée en fonction (pour racourcir d'autre fonctions), et betement aussi essaye de sortir le code de main() qui n'a rien a y faire (grosso modo, tout :d) et qui donc serait mieux dans une fonction
 

Reply

Marsh Posté le 10-11-2005 à 00:36:13    

oui oui le mutex quand je disai dans le main ,j'entendai par la dans chaque fonction ou je modifie une variable.
 
comment ca redecoupees? enfin je comprends c'que ca veut dire mais quoi par exemple?
Sinon pour le main en fait je compte laisser au final que de l'appel de fonction, c'est juste que tout ce qui reste n'a pas encore ete fait :D

Reply

Marsh Posté le 10-11-2005 à 00:36:38    

gocho a écrit :

un p'ti coup de malloc donc...j'vais commencer a bien le gerer celui la a la fin  :lol:
 
edit : attends attends...si je declare mon tableau de client avec un malloc.
il est donc NULL au debut.
Mais si je le remplis, ca veut dire realloc a chaque nouveau client/depart de client ?c'est bien ca ( :cry:  inside)?


 
bon, globalement, je verrais un truc comme ca (vite fait, hein, en me basant sur ton code)

Code :
  1. typedef struct _MonServeur
  2. {
  3.   client * tab_client;
  4.   char * nom_serveur;
  5.   int case_libre;
  6.   int nb_client;
  7. }MonServeur;
  8. MonServeur * CreerServeur(const char *nom, int maxClient)
  9. {
  10.    MonServeur res = malloc(sizeof(struct _MonServeur));
  11.    res->tabClient = malloc(sizeof(client) * maxclient);
  12.    res->case_libre = res->nb_client = 0:
  13.    res->nom_serveur = strdup(nom);
  14.    return res;
  15. }


 
(je torche un brin, pas de test ni rien)
 
et pour la suite des operations tu bosses sur ta structure "MonServeur"
 
 

Reply

Marsh Posté le 10-11-2005 à 00:38:27    

ok.donc du dynamique au maximum...on va essayer hein.
Par contre : a quoi sert le const? je l'ai deja vu mais jamais encore reussi a capter a quoi qu'il sert.

Reply

Marsh Posté le 10-11-2005 à 00:39:17    

gocho a écrit :

ok.donc du dynamique au maximum...on va essayer hein.
Par contre : a quoi sert le const? je l'ai deja vu mais jamais encore reussi a capter a quoi qu'il sert.


 
 
c'est du "je regarde, mais je touche pas"
 
donc la ca signifie que je prends une chaine en entree, mais que je "m'engage" (avec l'aide du compilo) a ne pas la modifier

Reply

Marsh Posté le 10-11-2005 à 00:41:28    

ok. parametre non modifiable par la fonction donc...
il me semble aussi en avoir deja vu sur la fonction non?
du genre const int machin_truc (arg1, arg2) c'est possible ca?
Et si oui ca sert a quoi?

Reply

Marsh Posté le 10-11-2005 à 00:41:58    

bin la ca veut dire que tu renvoie un entier const, ce qui est d'une utilité discutable

Reply

Marsh Posté le 10-11-2005 à 00:42:07    

(bon chu pu la, hein ? :d)

Reply

Marsh Posté le 10-11-2005 à 00:43:08    

ouep c'est clair...enfin c'est pas le sujet : je m'egare.
je sais maintenant comment occuper mon demain aprem' :)
edit : oue pareil moi non plus (bonne nuit inside) et pour ceux qui passent par la n'hesitez pas a poster pour me dire si vous voyez d'autres choses ;)


Message édité par gocho le 10-11-2005 à 00:43:59
Reply

Marsh Posté le 10-11-2005 à 07:07:45    

gocho a écrit :

ah...j'pensais bien que ca viendrait la.
Comme j'ai pas encore vraiment bien capte tout ca :  
La synchro c'est comment on la fait? c'est juste empecher deux threads d'acceder a la meme variable en meme temps avec les mutex c'est ca? (j'ai jete un coup d'oeil mais pas encore eu le temps de m'atteler a la tâche)


 
http://mapage.noos.fr/emdel/pthreads.htm


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 10-11-2005 à 08:45:16    

ok.donc faut que je vois du cote du mutex en parallele avec le pthread_join pour que ce soit optimal donc.
Plus qu'a faire tout ca maintenant...

Reply

Marsh Posté le 13-11-2005 à 22:45:46    

Re bonsoir.
Alors apres un peu de retard j'ai pu me replonger dans mon petit projet.
j'ai retravaille tout ca pour regler toutes les erreurs que j'avais lors de la compilation mais il en reste une que je comprends pas :  
Quand je compile gcc me renvoie un desagreable : collect2 : ld returned 1 exit status
 
Est ce que quelq'un pourrait me dire ce que ca veut dire (dois je reposter le code?)
merci bien :)

Reply

Marsh Posté le 13-11-2005 à 23:06:37    

pb de link, poste plutot l'erreur en entier

Reply

Marsh Posté le 13-11-2005 à 23:12:09    

je l'ai poste sur un sujet a part, je me dis que ca pourrait reservir a quelqu'un ;)
http://forum.hardware.fr/hardwaref [...] 0093-1.htm

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed