C Unix, pthread_create: échoue

J’ai besoin d’aide. Je m’excuse pour mon mauvais anglais. J’espère expliquer exactement mon problème. J’ai programmé un programme client / serveur en C Unix. Le serveur est multi-threading. Je n’ai eu aucun problème avec le serveur jusqu’à ce qu’il commence à manipuler des fichiers. Attention cependant, car le vrai problème ne réside pas dans la manipulation des fichiers: le serveur manipule les fichiers sans problème. Il ouvre et ferme ces fichiers plusieurs fois et lit et écrit en douceur. Le vrai problème: lorsque le client, qui a utilisé les services qui manipulent des fichiers, se déconnecte ou si un nouveau client souhaite se connecter lorsqu’un client précédent a utilisé les services de manipulation de fichiers, le serveur accepte la connexion, lance la fonction pthread_create Cela ne parvient pas à terminer la création du nouveau thread. Ensuite, la fonction de démarrage n’est pas exécutée. J’ai réalisé ce comportement car pthread_join renvoie l’erreur “argument invalide” et ma fonction de démarrage n’imprime pas “SERVER: nouveau thread créé!” et le même pthread_create ne renvoie pas la “valeur> 0” pour les erreurs. Je tiens à préciser que lorsque le serveur est démarré et que plusieurs clients sont lancés, tout fonctionne correctement. Mais dès qu’un client appelle un service manipulant un fichier, le serveur ne peut pas terminer la fonction pthread_create. Pourquoi est-ce? Je suis jours j’essaie de comprendre ce qui se passe. Qui m’aide? C’est la fonction qui crée le nouveau thread / s:

void gestisciConnessioni(int serverfdin, int numeroconnessioniIn, struct sockaddr_in *clientindirizzoin, int *connessioneclientin) { //Variabile/i locale/i: struct sockaddr *clientindirizzoptr; //Puntatore alla Struttura indirizzo del client int clientindirizzodim; //Dimensione dell'indirizzo del client char *indirizzoip; tipoinfoconnessioneclient *unainfoclient = NULL; pthread_t tid; int errore = -1; //Blocco codice: //Il server si mette in ascolto dei clients: if ((listen(serverfdin, numeroconnessioniIn)) != 0) { printf("SERVER: Attenzione, listening... fallito!\n"); exit(1); } //Preparazione indizzamento client: clientindirizzoptr = (struct sockaddr *) clientindirizzoin; clientindirizzodim = sizeof ((*clientindirizzoin)); //Inizio concorrenza: //Il Server accetta la connessione del client; //Verifica la presenza di errori; //Inizia l'elaborazione. while (1) { *connessioneclientin = accept(serverfdin, clientindirizzoptr, &clientindirizzodim); if ((*connessioneclientin) > -1) { indirizzoip = inet_ntoa((*clientindirizzoin).sin_addr); printf("SERVER: Nuova connessione stabilita con %s.\n", indirizzoip); unainfoclient = (tipoinfoconnessioneclient *) (malloc(sizeof (tipoinfoconnessioneclient))); (*unainfoclient).descrittorefile = *connessioneclientin; (*unainfoclient).indirizzoip = indirizzoip; errore = pthread_create(&tid, NULL, elaborazioneServizi, (void *) (unainfoclient)); if (errore != 0) { printf("SERVER: Impossibile creare un nuovo thread!\n"); printf("(SERVER, ERRORE: %s)\n", strerror(errore)); exit(1); } pthread_detach(tid); errore = pthread_join(tid, NULL); if (errore != 0) { printf("SERVER: Impossibile attendere la terminazione del thread!\n"); printf("(SERVER, ERRORE: %s)\n", strerror(errore)); exit(1); } } else { printf("SERVER: Attenzione, connessione con %s... fallita!\n", indirizzoip); exit(1); } } } 

C’est la fonction de départ:

 void *elaborazioneServizi(void *args) { //Varibile/i locale/i: tipoinfoconnessioneclient unainfo; tipoinfoutente giocatore; int n; char messaggioin[100]; char **messaggioSplittato = NULL; int risposta = 0; int scelta = -1; fd_set insiemelettura; int fdmassimo; //Blocco codice: unainfo = *((tipoinfoconnessioneclient *) args); //************************************************************************** //Inizializzazione giocatore: //************************************************************************** giocatore.ip = unainfo.indirizzoip; giocatore.nome = " "; giocatore.stato = 2; giocatore.ultimaposizione.x = -1; giocatore.ultimaposizione.y = -1; //************************************************************************** printf("SERVER: Sto dentro la funzione di avvio!\n"); fdmassimo = unainfo.descrittorefile; FD_SET(unainfo.descrittorefile, &insiemelettura); printf("SERVER: Nuovo Thread appena creato!\n"); select(fdmassimo + 1, &insiemelettura, NULL, NULL, NULL); while (risposta == 0) { if (FD_ISSET(unainfo.descrittorefile, &insiemelettura)) { //***************************************************************** if ((n = read(unainfo.descrittorefile, messaggioin, 100)) == -1) { printf("SERVER: Errore in ricezione messaggio!\n"); exit(1); } while (n == 0) { pthread_cond_wait(&condizione, &mutex); } pthread_cond_signal(&condizione); printf("SERVER: Messaggio ricevuto per SWICTH: %s\n", messaggioin); messaggioSplittato = messaggioAvettore(messaggioin, 5, 50); scelta = atoi(messaggioSplittato[0]); switch (scelta) { case 0: daiUscita(unainfo.descrittorefile, &risposta); break; case 1: daiRegistrazione(unainfo.descrittorefile, messaggioSplittato); break; case 2: daiLogin(unainfo.descrittorefile, messaggioSplittato); break; default: printf("SERVER: Servizio, non disponibile!\n"); risposta = 1; break; } //***************************************************************** } } printf("SERVER: Thread... eliminato!\n"); close(unainfo.descrittorefile); pthread_exit(NULL); } 

C’est la fonction qui effectue la manipulation d’un fichier.txt (le plus court parmi d’autres):

 void daiLogin(int canalecomunicazionein, char **messaggioin) { //Variabile/i locale/i: int dimensionemessaggio = (NICKNAME_DIMENSIONE + PASSWORD_DIMENSIONE) + 2; char *nomeutente = NULL; char *password = NULL; char messaggioletto[NICKNAME_DIMENSIONE + PASSWORD_DIMENSIONE]; char **messaggiosplittato = NULL; char *ssortingngaconvalidata = NULL; char *messaggioout = NULL; char tmp[3]; int trovato = 0; //Trovato indica un utente registrato (1) oppure da registrare (0) int *fd = NULL; int n = -1; //Blocco codice: pthread_mutex_lock(&mutex); printf("SERVER: Sto eseguendo la funzione daiLogin()\n"); nomeutente = messaggioin[1]; password = messaggioin[2]; printf("SERVER: (%s,%s)\n", nomeutente, password); fd = inizializzaFileInLettura("registrazioni.txt"); if (*fd != -1) { lseek(*fd, 0, SEEK_SET); while ((n = read(*fd, messaggioletto, dimensionemessaggio))&&(trovato == 0)) { messaggiosplittato = messaggioAvettore(messaggioletto, 3, dimensionemessaggio); if ((strcmp(messaggiosplittato[0], nomeutente) == 0)&&(strcmp(messaggiosplittato[1], password) == 0)) { trovato = 1; } free(messaggiosplittato); messaggiosplittato = NULL; } close(*fd); free(fd); fd = NULL; snprintf(tmp, sizeof (tmp), "%d", trovato); messaggioout = componiMessaggio(tmp, "X", "X", "X", "X", 10); n = write(canalecomunicazionein, messaggioout, 10); pthread_mutex_unlock(&mutex); } } 

pthread_create ne pas sortir erreur / s. Seule erreur provient de pthread_join qui dit “argument invalide”. J’utilise un seul FD (uniquement) qui est toujours ouvert et fermé (à chaque fois).

Vous ne pouvez pas pthread_join juste après avoir appelé pthread_detach . pthread_detach sur un thread s’assure que vous n’êtes pas obligé de le pthread_join .

Il est inutile de pthread_create et ensuite de pthread_join immédiatement après. Vous pourriez juste appeler la fonction vous-même à la place et vous épargner l’effort.

Vous avez un débordement de tampon ici: read(*fd, messaggioletto, dimensionemessaggio)

Ici FD_SET(unainfo.descrittorefile, &insiemelettura); la variable insi... n’est pas initialisée. Et en parlant de select , le code moderne ne devrait pas utiliser select du tout. Surtout depuis que vous êtes en train de filer, vous devez vous attendre à beaucoup de connexions. Cela signifie que vous allez dépasser la limitation cachée de fd_set qui est généralement de 1024 fds. Utilisez le poll place.

Dans daiLogin vous verrouillez un mutex, mais vous ne le déverrouillez pas if (*fd != -1) { est faux. Je parie que c’est la vraie raison pour laquelle vous pensez que pthread_create échoue. pthread_create n’échoue pas, c’est juste que votre thread n’imprime rien car le mutex est déjà verrouillé et pthread_join échoue car le thread est détaché.

Vous ne pouvez pas joindre un thread détaché .

Et de l’homme pthread_detach :

Une fois qu’un thread a été détaché, il ne peut plus être joint à pthread_join (3) ou peut être joint à nouveau.