std::thread::detach în C++

Desparte firul de obiectul std::thread: rulează mai departe singur și nu mai poate fi așteptat cu join.

Sintaxă
void detach();

Ce face std::thread::detach

După t.detach(), firul își continuă execuția independent, iar obiectul t nu mai reprezintă nimic (joinable() devine false). Nu mai ai cum să aștepți terminarea lui cu join().

Când main se termină, procesul se încheie și firele detașate sunt oprite brusc, oriunde s-ar afla. De aceea un fir detașat nu are voie să folosească variabile locale ale funcției care l-a pornit și trebuie să aibă propriul mod de a anunța că a terminat (de exemplu un std::promise).

În practică, detach se folosește rar. De cele mai multe ori join, std::jthread sau std::async sunt alegeri mai sigure.

Ce returnează

Nimic.

Exemple

Exemplul 1: Fir detașat care anunță rezultatul printr-un promise

Firul primește promisiunea prin mutare (nu folosește variabile locale ale lui main), iar main așteaptă rezultatul cu future::get().

#include <future>
#include <print>
#include <string>
#include <thread>

int main() {
    std::promise<std::string> promisiune;
    std::future<std::string> rezultat = promisiune.get_future();

    std::thread t([p = std::move(promisiune)]() mutable {
        p.set_value("raport generat");
    });
    t.detach();
    std::println("joinable după detach: {}", t.joinable());

    std::println("Rezultat: {}", rezultat.get());
}

Rezultat

joinable după detach: false
Rezultat: raport generat

Exemplul 2: Firul detașat poate fi oprit înainte să termine

main se termină după 50 ms, iar firul, care ar fi avut nevoie de 5 secunde, este oprit odată cu procesul. Câte mesaje „lucrez” apar depinde de rulare.

#include <chrono>
#include <print>
#include <thread>

int main() {
    std::thread([] {
        for (int i = 1; i <= 100; ++i) {
            std::println("lucrez {}", i);
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    }).detach();

    std::this_thread::sleep_for(std::chrono::milliseconds(120));
    std::println("main se termină");
}

Rezultat posibil (diferă la fiecare rulare)

lucrez 1
lucrez 2
lucrez 3
main se termină

Greșeli frecvente

  • Firul detașat folosește o variabilă locală (prin referință) a funcției care l-a pornit. Funcția se termină, variabila este distrusă, iar firul scrie în memorie invalidă.
  • Apelezi join() după detach(). Se aruncă std::system_error, pentru că firul nu mai este joinable.

Comenzi înrudite

  • std::thread: Pornește o funcție pe un fir de execuție separat, care rulează în paralel cu restul programului.
  • std::jthread: Fir de execuție care face join automat la distrugere și poate fi rugat să se oprească (stop_token).
  • std::promise: Capătul de scriere al unui std::future: un fir promite o valoare și o trimite cu set_value.
  • std::future: Un rezultat care va fi disponibil în viitor (de la std::async sau std::promise); get() îl așteaptă și îl returnează.