Ce face std::thread
std::thread t(f, a, b); pornește imediat f(a, b) pe un fir nou. Firul principal (main) continuă în paralel. Argumentele sunt copiate; pentru referințe folosește std::ref.
t.join() așteaptă ca firul să termine. Înainte ca obiectul std::thread să fie distrus, trebuie apelat join() sau detach(); altfel programul se oprește cu std::terminate. joinable() spune dacă mai trebuie apelat unul dintre ele.
Firele care afișează în același timp își amestecă mesajele într-o ordine imprevizibilă. În exemplele de mai jos fiecare fir își scrie rezultatul într-un loc separat, iar afișarea se face după join(), deci rezultatul este mereu același.
Parametri
| Parametru | Descriere |
|---|---|
functie |
Funcția, lambda sau obiectul apelabil rulat pe firul nou. |
argumente |
Argumentele, copiate în firul nou. |
Ce returnează
Un obiect care reprezintă firul de execuție. join() nu returnează nimic; rezultatele se trimit prin variabile, std::future sau std::promise.
Exemple
Exemplul 1: Două calcule în paralel
#include <numeric>
#include <print>
#include <thread>
#include <vector>
int main() {
std::vector<int> v(1000);
std::iota(v.begin(), v.end(), 1); // 1, 2, ..., 1000
long long suma1 = 0, suma2 = 0;
std::thread t1([&] { suma1 = std::accumulate(v.begin(), v.begin() + 500, 0LL); });
std::thread t2([&] { suma2 = std::accumulate(v.begin() + 500, v.end(), 0LL); });
t1.join();
t2.join();
std::println("{} + {} = {}", suma1, suma2, suma1 + suma2);
}
Rezultat
125250 + 375250 = 500500
Exemplul 2: Mai multe fire, fiecare cu rezultatul lui
Fiecare fir scrie doar în elementul lui din vector, deci nu e nevoie de sincronizare. Afișarea se face după ce toate au terminat.
#include <print>
#include <string>
#include <thread>
#include <vector>
int lungime(const std::string& oras) { return static_cast<int>(oras.size()); }
int main() {
std::vector<std::string> orase{"Iași", "Cluj-Napoca", "Constanța"};
std::vector<int> rezultate(orase.size());
std::vector<std::thread> fire;
for (std::size_t i = 0; i < orase.size(); ++i) {
fire.emplace_back([&, i] { rezultate[i] = lungime(orase[i]); });
}
for (auto& t : fire) t.join();
for (std::size_t i = 0; i < orase.size(); ++i) {
std::println("{}: {} octeți", orase[i], rezultate[i]);
}
}
Rezultat
Iași: 5 octeți
Cluj-Napoca: 11 octeți
Constanța: 10 octeți
Exemplul 3: Ordinea mesajelor nu este garantată
Dacă firele afișează direct, ordinea se schimbă de la o rulare la alta. De aceea exemplul nu este rulat la generarea paginii.
#include <print>
#include <thread>
int main() {
std::thread a([] { std::println("Firul A"); });
std::thread b([] { std::println("Firul B"); });
std::println("Firul principal");
a.join();
b.join();
}
Rezultat posibil (diferă la fiecare rulare)
Firul principal
Firul B
Firul A
Greșeli frecvente
- Uiți
join(). La distrugerea obiectuluistd::threadprogramul se oprește brusc custd::terminate. Foloseștestd::jthread, care facejoinautomat. - Două fire modifică aceeași variabilă fără
std::mutexsaustd::atomic. Este o „cursă de date” (data race): comportament nedefinit, cu rezultate greșite care apar doar uneori. - Capturezi prin referință (
[&]) variabila de buclăi. Până pornește firul,ise poate schimba; captureaz-o prin valoare ([&, i]).
Comenzi înrudite
std::jthread: Fir de execuție care face join automat la distrugere și poate fi rugat să se oprească (stop_token).std::thread::detach: Desparte firul de obiectul std::thread: rulează mai departe singur și nu mai poate fi așteptat cu join.std::mutex: Încuietoare pentru date comune: un singur fir de execuție o poate ține la un moment dat.std::async: Rulează o funcție (de obicei pe alt fir) și îți dă un std::future din care iei rezultatul mai târziu.std::ref: Împachetează o referință ca să poată fi transmisă prin funcții care copiază argumentele (thread, bind).