2014-12-15 9 views
25

È sicuro creare un nuovo thread all'interno di while loop? Ho provato in questo modo:È sicuro creare un nuovo thread in un loop?

std::thread thread(ClientLoop,clientSocket) 

Ma non appena la funzione restituisce genera l'errore.

while (true){ 
    cout << "Waiting for new connections" << endl; 
    clientSocket = accept(listenSocket, nullptr, nullptr); 
    cout << "Client connected" << endl; 
    new thread(ClientLoop,clientSocket);     
} 

In questo modo funziona, ma mi chiedo se non ci siano perdite di memoria. Grazie.

+5

Che cosa è esattamente l'errore? Potrebbe essere uno stack overflow in quanto si tratta di un ciclo infinito che accetta semplicemente troppe connessioni? – Codor

+0

getta R6010 - abort() è stato chiamato – Tomas

+0

Nota che generare un nuovo thread è * costoso *. È abbastanza probabile che l'elaborazione dei dati in serie richiederà più tempo rispetto alla creazione del thread, quindi non farlo alla cieca sperando in un facile parallelismo. – Mehrdad

risposta

28

non appena tornare la funzione che genera l'errore

In effetti, non si deve distruggere un oggetto thread accostabile. Se avete bisogno di attendere il completamento del thread più tardi, poi staccarlo:

std::thread thread(ClientLoop,clientSocket); 
thread.detach(); 
// OK to destroy now 

Se hai bisogno di unirsi in un secondo momento, quindi si dovrà archiviare da qualche parte che persiste al di là del ciclo, ad esempio

std::vector<std::thread> threads; 
while (whatever){ 
    clientSocket = accept(listenSocket, nullptr, nullptr); 
    threads.emplace_back(ClientLoop,clientSocket); 
} 

// later 
for (std::thread & t : threads) { 
    t.join(); 
} 

// OK to destroy now 
threads.clear(); 

In questo modo funziona, ma mi chiedo se non ci sono perdite di memoria.

Sì, questo perde. Ogni new crea un oggetto thread e si elimina il puntatore senza eliminarlo o assegnarlo a un puntatore intelligente di cui occuparsi. Come menzionato nei commenti, non solo perde memoria, ma anche handle di thread, che su alcuni sistemi sono una risorsa più scarsa; quindi dopo un po 'potresti scoprire che non puoi lanciare altri thread.

Scollegare una filettatura è il modo di lasciarlo in esecuzione in background senza perdite. Questo fa sì che il thread rilasci le sue risorse quando finisce.

+5

Non è solo una perdita di memoria. I thread in genere utilizzano le risorse di sistema fino a quando non vengono uniti, o terminano se sono staccato. In questo caso, ci sono buone probabilità che inizi a fallire a causa di troppi thread molto prima che finisca la memoria. –

+0

grazie, ho appena usato il detach(), perché non ho bisogno di sincronizzare alcun thread. – Tomas

+0

Un thread distaccato è anche chiamato thread daemon? – 0x499602D2

9

Non c'è alcun problema nel creare il thread in un ciclo, ma potrebbe esserci un problema nel risolvere alla fine del ciclo se è una variabile locale. Per essere legalmente destrutturato, un oggetto thread deve essere detach ed, join o spostato. Se le tue discussioni sono semplicemente “ attiva e dimentica ” e non devi mai sincronizzarle con in seguito (anche per un arresto pulito), quindi chiama semplicemente std::thread::detach sul thread dopo averlo creato. Altrimenti, puoi inserirlo in un std::vector<std::thread>, quindi che puoi trovarlo e unirlo a volte più tardi.

+0

... o avvolgilo in oggetto RAII con comportamento personalizzato nel distruttore – Drop

+0

non dovrebbe essere sufficiente un join_all? – deW1

+0

grazie, questa è anche una risposta corretta, ma ho dovuto contrassegnare l'altra a causa del fatto che ha più spiegazioni – Tomas

5

sembra che non si voglia gestire la durata del thread (questo è quasi sempre un errore).

Se si vuole veramente fare questo, è fatto in questo modo:

while (true){ 
    cout << "Waiting for new connections" << endl; 
    clientSocket = accept(listenSocket, nullptr, nullptr); 
    cout << "Client connected" << endl; 
    thread t(ClientLoop,clientSocket); 
    t.detach(); // detach the actual thread from its std::thread handle 
} 
+2

'questo è quasi sempre un errore' - perché? È un thread accept() e probabilmente deve essere eseguito per tutta la durata del processo. I thread di durata del processo sono tutt'altro che insoliti. –

+3

La risposta breve è che la generazione di thread illimitati non è una soluzione scalabile. Alla fine sarà necessario convertire la logica in un modello asincrono con un pool di thread o connessioni di accelerazione contro un limite superiore. –

+0

Sarebbe un bel commento se avessi effettivamente suggerito di generare thread illimitati. Dal momento che non l'ho fatto ... –

Problemi correlati