Come posso terminare un thread in C ++ 11?


Risposte:


138
  1. Puoi chiamare std::terminate()da qualsiasi thread e il thread a cui ti riferisci terminerà forzatamente.

  2. È possibile disporre l' ~thread()esecuzione sull'oggetto del thread di destinazione, senza intervenire join()detach()su quell'oggetto. Ciò avrà lo stesso effetto dell'opzione 1.

  3. È possibile progettare un'eccezione che ha un distruttore che genera un'eccezione. E quindi organizzare che il thread di destinazione generi questa eccezione quando deve essere terminato forzatamente. La parte difficile di questo è ottenere il thread target per lanciare questa eccezione.

Le opzioni 1 e 2 non perdono risorse interne al processo, ma terminano ogni thread.

L'opzione 3 probabilmente perderà risorse, ma è parzialmente cooperativa in quanto il thread target deve accettare di lanciare l'eccezione.

In C ++ 11 (di cui sono a conoscenza) non esiste un modo portatile per uccidere in modo non cooperativo un singolo thread in un programma multi-thread (ovvero senza uccidere tutti i thread). Non c'era motivazione per progettare una tale caratteristica.

A std::threadpuò avere questa funzione membro:

native_handle_type native_handle();

Potresti essere in grado di utilizzarlo per chiamare una funzione dipendente dal sistema operativo per fare ciò che desideri. Ad esempio sui sistemi operativi Apple, questa funzione esiste ed native_handle_typeè a pthread_t. Se si riesce, è probabile che si verifichino perdite di risorse.


2
Leggero pignolo su "non perdere risorse interne al processo" : mentre è ovviamente vero che il sistema operativo recupererà tutte le risorse dopo aver ucciso il processo, le risorse sono trapelate per quanto riguarda il programma. Questo di solito è irrilevante, ma in alcuni casi può comunque rappresentare un problema. std::terminatené chiama distruttori statici né svuota i buffer di output, quindi l'ordine in cui vengono rilasciate le risorse non è ben definito, né hai alcuna garanzia che i tuoi dati siano visibili all'utente o scritti in un archivio permanente, o addirittura coerente e completo.
Damon,

6
Puoi anche chiamare exit()o abort()allo stesso effetto complessivo.
n. 'pronomi' m.

2
# 1 è uno scherzo e @ChrisDodd ha ragione. Lo scherzo è spiegato nella risposta nella prima frase al punto 3. Vedi anche la risposta di Nanno Langstraat e i commenti sottostanti.
Howard Hinnant,

43

La risposta di @Howard Hinnant è sia corretta che completa. Ma potrebbe essere frainteso se viene letto troppo rapidamente, perché std::terminate()(l'intero processo) sembra avere lo stesso nome del "termine" che @AlexanderVX aveva in mente (1 thread).

Riepilogo: "termina 1 thread + forzatamente (il thread target non collabora) + pure C ++ 11 = Assolutamente no."


14
Ahh, il mio numero 1 è davvero divertente. Non è necessario specificare quale thread si desidera terminare forzatamente. Il sistema sa magicamente quale vuoi finire con forza e lo fa!
Howard Hinnant,

8
Sì, la std::terminate()risposta è come una classica malvagia storia di Djinn; soddisfa tutto il desiderio del PO alla lettera, anche se probabilmente non nel modo in cui intendeva . L'umorismo discreto mi ha fatto sorridere. :-)
Nanno Langstraat il

2
Devo solo impedire ai neofiti del C ++ innocenti di sperare troppo o troppo a lungo.
Nanno Langstraat,

2
Dichiarato elegantemente. :-)
Howard Hinnant

@NannoLangstraat dammnit ... Avevo grandi speranze, fino a quando non ho letto: (..lol, oh beh + 1 è tutto intorno
:)

13

Questa domanda in realtà ha una natura più profonda e una buona comprensione dei concetti di multithreading in generale ti fornirà informazioni su questo argomento. In effetti, non esiste alcuna lingua o alcun sistema operativo che fornisca servizi per la terminazione brusca asincrona del thread senza preavviso per non usarli. E tutti questi ambienti di esecuzione consigliano vivamente lo sviluppatore o richiedono persino la creazione di applicazioni multithreading sulla base della terminazione di thread cooperativa o sincrona. Il motivo di queste decisioni e consigli comuni è che tutti sono costruiti sulla base dello stesso modello di multithreading generale.

Confrontiamo i concetti di multiprocessing e multithreading per comprendere meglio i vantaggi e i limiti del secondo.

Il multiprocessing presuppone la suddivisione dell'intero ambiente di esecuzione in una serie di processi completamente isolati controllati dal sistema operativo. Il processo incorpora e isola lo stato dell'ambiente di esecuzione, compresa la memoria locale del processo e dei dati al suo interno e tutte le risorse di sistema come file, socket, oggetti di sincronizzazione. L'isolamento è una caratteristica di fondamentale importanza del processo, poiché limita la propagazione dei guasti da parte dei bordi del processo. In altre parole, nessun processo può influire sulla coerenza di un altro processo nel sistema. Lo stesso vale per il comportamento del processo, ma nel modo meno limitato e più sfocato. In tale ambiente qualsiasi processo può essere interrotto in qualsiasi momento "arbitrario", poiché in primo luogo ogni processo è isolato, in secondo luogo,

Al contrario, il multithreading presuppone l'esecuzione di più thread nello stesso processo. Ma tutti questi thread condividono la stessa casella di isolamento e non esiste alcun controllo del sistema operativo sullo stato interno del processo. Di conseguenza, qualsiasi thread è in grado di modificare lo stato del processo globale e di corromperlo. Allo stesso tempo, i punti in cui è noto che lo stato del thread è sicuro per eliminare completamente un thread dipende dalla logica dell'applicazione e non sono noti né per il sistema operativo né per il runtime del linguaggio di programmazione. Di conseguenza, terminare il thread nel momento arbitrario significa ucciderlo in un punto arbitrario del suo percorso di esecuzione e può facilmente portare alla corruzione dei dati a livello di processo, alla memoria e alla gestione delle perdite,

Per questo motivo l'approccio comune è quello di forzare gli sviluppatori a implementare la terminazione di thread sincrona o cooperativa, in cui un thread può richiedere la terminazione di altri thread e l'altro thread in un punto ben definito può controllare questa richiesta e avviare la procedura di arresto dallo stato ben definito rilasciando tutte le risorse globali a livello di sistema e le risorse locali a livello di processo in modo sicuro e coerente.


8
Questa non è una risposta molto utile. La multielaborazione non è pertinente qui e le osservazioni sul multi-threading sono piuttosto ampie.
MSalters

4
Quello che volevo dire e dire in dettaglio è che il modello multithreading non fornisce un modo formale di terminazione forzata del thread. C ++ vuole seguire i modelli chiari tra cui il modello di memoria, il modello multithreading, ecc. Il metodo di terminazione forzata del thread non è intrinsecamente sicuro. Se il comitato standard C ++ fosse costretto ad aggiungerlo a C ++, verrebbe creato con la prossima istruzione "Metodo terminate () termina l'esecuzione del thread. Comportamento indefinito.", Che sembrerà "fare un po 'di magia e (possibilmente) terminare il thread ".
ZarathustrA

C # ha questa funzione.
Derf Skren,

@Derf Skren "In realtà non esiste alcuna lingua o alcun sistema operativo che fornisca servizi per la terminazione improvvisa asincrona del thread senza preavviso per non usarli" (c) ZarathustrA "Note: Importante! Il metodo Thread.Abort deve essere usato con cautela In particolare quando lo chiami per interrompere un thread diverso dal thread corrente, non sai quale codice è stato eseguito o non è stato eseguito ... "(c) Collegamento Microsoft: docs.microsoft.com/en-us/dotnet/ api /…
ZarathustrA

11

Suggerimenti sull'uso della funzione dipendente dal sistema operativo per terminare il thread C ++:

  1. std::thread::native_handle()può solo ottenere il tipo di handle nativo valido del thread prima di chiamare join()o detach(). Dopodiché, native_handle()restituisce 0 - pthread_cancel()verrà coredump.

  2. Per chiamare in modo efficace la funzione di terminazione del thread nativo (ad es. pthread_cancel()), È necessario salvare l'handle nativo prima di chiamare std::thread::join()o std::thread::detach(). In modo che il terminatore nativo abbia sempre un handle nativo valido da utilizzare.

Ulteriori spiegazioni si prega di fare riferimento a: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread .


5

Immagino che il thread che deve essere ucciso sia in qualsiasi tipo di modalità di attesa o che faccia un lavoro pesante. Suggerirei di usare un modo "ingenuo".

Definisci alcuni booleani globali:

std::atomic_bool stop_thread_1 = false;

Inserisci il seguente codice (o simile) in diversi punti chiave, in modo da far tornare tutte le funzioni nello stack di chiamate fino a quando il thread non termina naturalmente:

if (stop_thread_1)
    return;

Quindi per interrompere il thread da un altro thread (principale):

stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.