2012-12-15 12 views

risposta

22

Non è possibile.

std::threads non sono interrompibili. È possibile utilizzare boost::thread che offre questa funzionalità.

Boost esegue questa operazione definendo i "punti di interruzione" su cui terminerà il thread se viene interrotto e raggiunge tale punto.

Tuttavia, il più delle volte pensare a una riprogettazione potrebbe essere il modo più semplice e pulito per raggiungere ciò che si sta cercando di ottenere.

Se si sta ancora cercando un'implementazione di thread interrompibili in C++ 11, Anthony Williams (proprietario del thread di boost) prenota "C++ Concurrency in Action". Egli passa attraverso una implementazione di base di come una cosa del genere può essere raggiunta.

std::thread::native_handle consente di accedere alla maniglia di thread sottostante specifica della piattaforma che potrebbe supportare l'interruzione, tuttavia questo approccio rende il codice non modificabile e probabilmente non più pulito in alcun modo.

34

@ la risposta di bamboon è buona, tuttavia ritengo che questo meriti una dichiarazione più forte.

Qualunque sia la lingua che usi, il tuo programma acquisirà e rilascerà risorse: memoria, descrittori di file, ... Per i programmi semplici che vengono sparati in un colpo, la perdita di risorse non conta molto: quando il programma termina automaticamente i sistemi operativi moderni riprendere le risorse; tuttavia, per i programmi di lunga durata un requisito fondamentale non è quello di perdere risorse, o almeno non ripetitivamente.

Pertanto, è necessario è stato insegnato fin dall'inizio che quando si acquista una risorsa si dovrà assicurarsi che sia rilasciato a un certo punto:

void foo(int i) { 
    int* array = malloc(sizeof(int) * i); 

    /* do something */ 

    free(array); 
} 

Quindi, porsi la domanda:

  • cosa succede quando uccido il programma?
  • cosa succede quando uccido il thread?

Beh, come abbiamo detto, quando un programma termina il sistema operativo raccoglie le risorse indietro, in modo da assumere (e questo è un po 'ipotesi) che non hai acquisire una risorsa un altro sistema O che questo sistema va bene protetto da tale abuso, nessun danno, nessun fallo.

Tuttavia, quando si uccide un thread, il programma viene comunque eseguito, quindi il sistema operativo non raccoglie le risorse. Di memoria trapelata, hai bloccato un file per la scrittura che non puoi più sbloccare, ... Non devi uccidere i thread.

I linguaggi di livello superiore hanno un modo per gestire questo: eccezioni. Poiché i programmi dovrebbero essere comunque sicuri delle eccezioni, Java (ad esempio) ucciderà un thread mettendolo in pausa, generando un'eccezione nel punto di esecuzione e rilassando delicatamente lo stack. Tuttavia non esiste ancora una tale funzionalità in C++.

È impossibile? No, ovviamente no. In realtà, si potrebbe perfettamente riutilizzare la stessa idea:

  • incapsulare std::thread, interruptible_thread classe conterrà anche una bandiera interrupt
  • passare l'indirizzo della bandiera per std::thread al momento del lancio, e conservarla in un filettatura modo locale
  • strumento il codice con punti di controllo in cui si controlla se il flag di interrupt è impostato o meno, e quando si tratta di un'eccezione

Cioè:

// Synopsis 
class interrupt_thread_exception; 
class interruptible_thread; 
void check_for_interrupt(); 

// Interrupt exception 
class interrupt_thread_exception: public virtual std::exception { 
public: 
    virtual char const* what() const override { return "interrupt"; } 
}; // class interrupt_thread_exception 

// Interruptible thread 
class interruptible_thread { 
public: 
    friend void check_for_interrupt(); 

    template <typename Function, typename... Args> 
    interruptible_thread(Function&& fun, Args&&... args): 
     _thread([](std::atomic_bool& f, Function&& fun, Args&&... args) { 
        _flag_ref = &f; fun(std::forward<Args>(args)...); 
       }, 
       _flag, 
       std::forward<Function>(fun), 
       std::forward<Args>(args)...) 
    {} 

    bool stopping() const { return _flag.load(); } 

    void stop() { _flag.store(true); } 

private: 
    static thread_local std::atomic_bool* _flag_ref = nullptr; 

    std::atomic_bool _flag = false; 
    std::thread _thread; 
}; // class interruptible_thread 

// Interruption checker 
inline void check_for_interrupt() noexcept(false) { 
    if (not interruptible_thread::_flag_ref) { return; } 
    if (not interruptible_thread::_flag_ref->load()) { return; } 

    throw interrupt_thread_exception(); 
} // check_for_interrupt 

Ora è possibile semplicemente cospargere il codice filettato con controlli per l'interruzione nelle posizioni appropriate.

+5

+1, ** questo ** è un concetto così importante. I thread sono in un diverso dominio di risorse e sicurezza per i processi. Richiedono un approccio cooperativo piuttosto che "contraddittorio". Riforma il codice in modo che i thread possano terminare correttamente quando richiesto. –

+1

'void foo (int)' non è già sicuro, se hai un controllo di interruzione nel mezzo di '/ * fai qualcosa */'sarà ancora sbagliato. –

+0

Quale segnale? Stai parlando di generare un'eccezione durante l'interruzione e alcune piattaforme fanno lo stesso per pthread_cancel. Se viene lanciata un'eccezione, la funzione non viene completata. –

Problemi correlati