Domanda Voglio uccidere uno std :: thread usando il suo oggetto thread? [duplicare]


Possibile duplicato:
Interruzione del thread C ++ 0x 

Sto cercando di uccidere / fermare un c ++ std :: thread usando il suo oggetto thread.

Come possiamo farlo?


23
2017-12-15 14:28


origine


risposte:


@ 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 solo colpo, le perdite di risorse non contano molto: quando il programma termina, i sistemi operativi moderni recuperano automaticamente le risorse ; tuttavia, per i programmi di lunga durata un requisito fondamentale non è quello di perdere risorse, o almeno non ripetitivamente.

Pertanto, ti sarebbe stato insegnato fin dall'inizio che quando acquisisci una risorsa devi assicurarti che venga rilasciato in un punto:

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

    /* do something */

    free(array);
}

Quindi, poniti la domanda:

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

Bene, come abbiamo detto, quando un programma termina, il sistema operativo recupera le risorse, quindi supponendo (e questo è un dato di fatto) che non hai acquisito una risorsa su un altro sistema O che questo sistema è ben 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. Hai dimenticato la memoria, hai bloccato un file per la scrittura che non puoi più sbloccare, ... Non uccidere i fili.

Le lingue 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à, potresti riutilizzare perfettamente la stessa idea:

  • incapsulare std::thread, interruptible_thread la classe conterrà anche un flag di interrupt
  • passare l'indirizzo della bandiera a std::thread quando lo si avvia e lo memorizza in un thread locale
  • strumenta il tuo codice con i punti di controllo in cui controlli se il flag di interrupt è impostato o meno e quando viene lanciata un'eccezione

Questo è:

// 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 puoi semplicemente cospargere il codice filettato con controlli per l'interruzione nei luoghi appropriati.


37
2017-12-15 15:14



Non puoi

std::threads non sono interrompibili. Puoi usare boost::thread che offre questa funzionalità.

Boost fa questo 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ù pulito e semplice per raggiungere ciò che si sta cercando di ottenere.

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

std::thread::native_handleti dà accesso al thread handle specifico della piattaforma che potrebbe supportare l'interruzione, tuttavia questo approccio rende il tuo codice non modificabile e probabilmente non più pulito in alcun modo.


23
2017-12-15 14:41