Newsgroup: it.comp.lang.c
Titolo: Problemi con pThread

Ciao a tutti!
 
Ho scritto un programma che ascolta su una certa porta TCP.
Ogni volta che si presenta un client crea un nuovo pThread per servirlo.
Il pThread, quando ha finito il suo lavoro si chiude con pthread_exit.
 
Il sistema funzionerebbe anche, ma ogni due giorni circa capita che
pthread_create non riesca piu' a creare un nuovo pThread e l'unica
soluzione e' il riavvio del programma...
 
Questo e' il codice che uso per creare il pThread:
 
  SOCKET sock;
  struct sockaddr_in cli_addr;
  socklen_t clilen;
  struct threadArgs tArgs;
  pthread_t socketTID;
 
  listen(sockfd, 5);
  clilen = sizeof(cli_addr);
  sock = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen );
 
  if(sock != -1)
  {
    tArgs.sock = sock;
    if(pthread_create(&socketTID, NULL, (void *)&socketThread, (void
*)&tArgs) != 0)
    {
      sendToRemote(sock, "FATAL ERROR. Closing connectionn");
      close(sock);
      LOGGER(LOGL_ERROR, "Unable to create pThread!");
    }
  }
 
Cosa faccio di sbagliato?
 
Grazie
Luca Bertoncello
(
luca...@lucabert.de
)
 
-- 
 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it
 
 
 

    }
...
 
Ciao,
la parte di codice che hai postato è piuttosto "essenziale",
nel senso che non so se il problema che hai dipenda _solo_ da questa.
Di sicuro ci sono delle correzioni da fare in queste righe.
La struttura di un semplice server dovrebbe essere di questo tipo:
 
/*
  *   dichiarazione descrittori dei socket-server e socket-client
  */
int serverSocket, clientSocket;
 
/*
  *   creazione del socket-server che accetterà le connessioni
  */
if( (serverSocket = socket(...)) < 0 )
     /* gestisci errore */
 
     struct sockaddr_in serverAddress;
     memset(&serverAddress, 0, sizeof(serverAddress));
     /* inizializzazione di serverAddress */
 
/*
  *   binding del server al suo indirizzo
  */
if( bind(serverSocket,
          (struct sockaddr *)&serverAddress,
          sizeof(serverAddress)) < 0 )
{
     /* gestisci errore */
}
 
/*
  *   metti il socket-server in ascolto (tu non testi il valore di
  *   ritorno di listen(), inoltre ti consiglio di usare delle macro
  *   al posto di costanti numeriche come 5)
  */
if( listen(serverSocket, 5) < 0 )
     /* gestisci errore */
 
 
 
/*
  *   questo è il classico loop "infinito" che permette al server di
  *   accettare connessioni dal client (finchè il client vuole
  *   inviare richieste di connessione). Questo loop nel tuo codice
  *   è assente, quindi in caso il server non accetti la connessione
  *   in prima istanza non aspetterà più altre richieste dal client
  */
 
do {
 
     struct sockaddr_in clientAddress;
     socklen_t clientAddresslenght = sizeof(clientAddress);
 
     clientSocket = accept(serverSocket,
                           (struct sockaddr *)&clientAddress,
                           &clientAddressLenght);
     if(clientSocket < 0)
         /* gestisci errore */
 
     /* qui puoi creare il pthread che servirà il client */
 
     close(clientSocket);
 
while( il_client_vuole_ancora_connettersi );
 
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 

 while( il_client_vuole_ancora_connettersi );
 
 
ho dimenticato di chiudere la parentesi graffa del "do" quindi leggi:
 
} while( il_cliente_vuole_ancora_connettersi );
 
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 

 La struttura di un semplice server dovrebbe essere di questo tipo:
 
Si, lo so che e' essenziale, ma il fatto e' che il resto (apertura del
Socket, bind, etc.) e' fatto da un'altra parte e funziona senza problemi,
tant'e' che riesco SEMPRE a collegarmi.
 
Il problema avviene proprio quando tento di creare un nuovo pThread. Ed e'
appunto nel codice che ho mandato...
 
Ciao



Hai provato a chiedere direttamente a lei? :-)
ret = pthread_create(&socketTID, NULL, (void *)&socketThread,
(void*)&tArgs);
if (ret==EAGAIN) {
    /* questo è ok, magari basta aspettare... */
    continue;
} else {
    /* facciamoci dire l'errore */
    perror("pthread_create");
}
Ciao!

 }
 
Adesso ho modificato il programma per farmi dire l'errore, anche se ho i
miei dubbi che sia qualcosa che posso modificare...
Dalle man pages vedo che, oltre a EAGAIN, che non dovrebbe essere un
problema in quanto basta attendere, gli altri due errori sono per
parametri sbagliati, a meno che non abbia capito male.
 
E come puo' essere sbagliato un parametro che per due giorni era giusto?
 
Ciao


 E come puo' essere sbagliato un parametro che per due giorni era giusto?
 
gdb is your friend ...

 [...]
 
Ciao  Manlio


 
Ah beh, ci sono un milione di possibilità diverse: la prima tra tutte
(anche se magari non sarà il tuo caso visto che l'esaurimento di
risorse è la causa più probabile) è che per un qualsiasi motivo (UB,
BO, o semplice bug generico) la memoria viene corrotta con una
scrittura sbagliata.
 
Ciao!

 2) Quanti client contemporanei stai servendo quando ottieni l'errore?
 
Due... :(
Attualmente il sistema non e' proprio molto utilizzato, per fortuna!
 
Ciao


 gdb is your friend ...
 
E' un po' dura farlo sul Server... Sul mio PC, che uso per lo sviluppo,
non ha problemi.
E, come ho detto, gira per un paio di giorni prima di dare errori...


   (assumo sia POSIX)
 
Bon, sono riuscito a farlo andare in errore (semplicemente mandandogli
tante richieste ripetute).
 
L'errore e' l'11, ossia EAGAIN, peccato che anche ritentare dopo non porti
nessun risultato...
 
Una cosa e' pero' importante: questo errore l'ho prodotto con il
pthread_detach commentato, in quanto volevo essere nella stessa situazione
di ieri (e dei giorni prima).
 
Ora ho rimesso pthread_detach e ho rilanciato il test. Vediamo se si
incricca o se ho trovato il problema...
 
Ciao


 incricca o se ho trovato il problema...
 
Adesso, con la pthread_detach sembra girare stabile...
Quantomeno non sono ancora riuscito a farlo incriccare...
 
Boh?!? Magari e' solo questo...



 
Bon, allora già che ci sei contati i create e i detach totali, almeno
all'errore saprai subito se esiste un ramo di codice che o 1) pianta
il thread o 2) salta il detach. :-)
Ciao!

 E, come ho detto, gira per un paio di giorni prima di dare errori...
 
Se non riesci a replicare il problema sul PC di sviluppo e soprattutto se 
non trovi l'errore (chiudi tutti i socket? I thread li detach-i o li join-
i al termine ? Hai provato valgrind se tice qualcosa di utile ?) allora 
quando il programma si inceppa sul server ti ci attacchi con gdb e cerchi 
di capire dove sia e quale sia il problema.
 
A meno che tu non abbia la palla di cristallo, ovviamente.

 il thread o 2) salta il detach. :-)
 
Allora, partiamo dal presupposto che sono piuttosto nuovo alla
programmazione con pThreads...
 
Adesso ho fatto in modo che dopo ogni create venga chiamata una detach.
 
E cosi' pare funzionare in maniera stabile, anche se "chiudero' il Bug"
non prima della fine della settimana prossima...
 
Quello che pero' ora vorrei capire e': perche' devo dare una detach?
O, meglio, partendo dal fatto che una detach o una join siano
obbligatorie, perche' mai SENZA la detach funziona per qualche giorno?
 
Grazie


 [...]
 
 
Ciao  Manlio

 perche' mai SENZA la detach funziona per qualche giorno?
 
Perchè le risorse di qualunque sistema non sono infinite.
 
 
 
man pthread_detach
 
DESCRIPTION
       The  pthread_detach()  function  marks the thread identified by 
thread as detached.  When a detached thread terminates, its resources are 
automatically released back to the system without the need for another 
thread to join with the terminated thread.
 

 thread to join with the terminated thread.
 
E questo invece non l'avevo letto (bene)...
 
Ok, allora direi che e' normale che, adesso che uso una detach, tutto
funzioni.
Ed anche che, un altro programma che feci al tempo con una pthread_join,
funzionasse.
 
Grazie mille a tutti!


 
 
Mi sembra spiegato abbastanza chiaramente nella documentazione:
linux.die.net/man/3/pthread_detach
 
 
Quando un thread termina, il sistema operativo non può deallocare tutta 
la struttura dati associata al thread stesso, perchè se qualcuno fa il 
join c'è bisogno di "ricordare" quale valore ha restituito il thread.
 
 
Ciao  Manlio

 join c'è bisogno di "ricordare" quale valore ha restituito il thread.
 
OK! Ho semplicemente bisogno di FERIE!!
 
Grazie ancora a tutti!
