std::thread
Főnév
std::thread (tsz. std::threads)
- (informatika) Az std::thread a C++ szabványos könyvtárának része, amely lehetővé teszi a többszálú programozást (multithreading). A többszálúság azt jelenti, hogy egy program egyszerre több szálon (thread) is futhat, ami párhuzamos végrehajtást és teljesítményjavulást eredményezhet.
Ebben a részletes útmutatóban bemutatjuk az std::thread használatát, az alapvető műveleteket, a szinkronizációs eszközöket és néhány gyakori hibát.
1. std::thread alapjai
A std::thread segítségével egy új végrehajtási szálat hozhatunk létre. A szál egy függvény végrehajtását végzi el, amely lehet: - Egy normál függvény - Egy lambda kifejezés - Egy osztály tagfüggvénye
Egyszerű std::thread példa
#include <iostream>
#include <thread>
void szamolas() {
for (int i = 0; i < 5; i++) {
std::cout << "Számolás: " << i << std::endl;
}
}
int main() {
std::thread szal(szamolas); // Létrehozunk egy szálat
szal.join(); // Megvárjuk a szál végét
std::cout << "Főprogram vége." << std::endl;
return 0;
}
Magyarázat:
- std::thread szal(szamolas); → Elindít egy új szálat, amely a
szamolasfüggvényt futtatja. - szal.join(); → A főprogram megvárja, hogy a szál befejezze a végrehajtást.
2. Több szál futtatása
Ha több szálat szeretnénk egyidejűleg elindítani, minden szálhoz külön std::thread példányt hozunk létre.
Több szál futtatása
#include <iostream>
#include <thread>
void munka(int id) {
for (int i = 0; i < 5; i++) {
std::cout << "Szál " << id << ": " << i << std::endl;
}
}
int main() {
std::thread szal1(munka, 1);
std::thread szal2(munka, 2);
szal1.join();
szal2.join();
std::cout << "Főprogram vége." << std::endl;
return 0;
}
Itt két különálló szál fut párhuzamosan, mindkettő a munka függvényt végzi el.
3. Szál kezelése – join() és detach()
Az std::thread objektumokat megfelelően kell kezelni, különben a program összeomolhat.
join() – Megvárja a szál végét
A join() segítségével a főprogram várakozik, amíg a szál befejezi a futását.
std::thread szal(munka);
szal.join(); // Megvárjuk, hogy a szál befejezze a munkáját
Ha nem hívjuk meg a join() függvényt, a program összeomolhat, mert a szál objektum megsemmisülne, miközben még fut.
detach() – Leválasztja a szálat
A detach() segítségével a szál függetlenül fut tovább, és a főprogram nem vár rá.
std::thread szal(munka);
szal.detach(); // A szál függetlenül fut tovább
A detach() használatakor biztosítani kell, hogy a szál hozzáférhető maradjon a memória felszabadításáig, különben undefined behavior léphet fel.
4. Szinkronizáció és versenyhelyzetek
Ha több szál módosítja ugyanazt az adatot, versenyhelyzetek alakulhatnak ki.
Versenyhelyzet példája
#include <iostream>
#include <thread>
int szamlalo = 0;
void novel() {
for (int i = 0; i < 1000; i++) {
szamlalo++; // Versenyhelyzet
}
}
int main() {
std::thread szal1(novel);
std::thread szal2(novel);
szal1.join();
szal2.join();
std::cout << "Számláló értéke: " << szamlalo << std::endl; // Nem biztos, hogy 2000 lesz!
return 0;
}
A program nem garantálja, hogy a szamlalo értéke 2000 lesz, mert a két szál egyszerre próbálja módosítani.
5. Mutex – Kölcsönös kizárás
A versenyhelyzetek elkerülésére használhatunk std::mutex-et.
#include <iostream>
#include <thread>
#include <mutex>
int szamlalo = 0;
std::mutex mtx;
void novel() {
for (int i = 0; i < 1000; i++) {
std::lock_guard<std::mutex> lock(mtx); // Biztosítja, hogy egyszerre csak egy szál írhatja
szamlalo++;
}
}
int main() {
std::thread szal1(novel);
std::thread szal2(novel);
szal1.join();
szal2.join();
std::cout << "Számláló értéke: " << szamlalo << std::endl; // Most garantáltan 2000
return 0;
}
Itt a mutex (mtx) biztosítja, hogy egyszerre csak egy szál módosíthatja a változót.
6. Deadlock és megoldása
Ha több mutexet használunk, előfordulhat holtverseny (deadlock).
Deadlock példa
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx1, mtx2;
void f1() {
mtx1.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
mtx2.lock(); // Deadlock lehetséges
std::cout << "f1 fut" << std::endl;
mtx2.unlock();
mtx1.unlock();
}
void f2() {
mtx2.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
mtx1.lock(); // Deadlock lehetséges
std::cout << "f2 fut" << std::endl;
mtx1.unlock();
mtx2.unlock();
}
int main() {
std::thread t1(f1);
std::thread t2(f2);
t1.join();
t2.join();
return 0;
}
A megoldás az std::lock(), amely egyszerre próbálja lezárni a mutexeket.
std::lock(mtx1, mtx2);
7. Condition Variables (Feltételes változók)
A std::condition_variable lehetővé teszi, hogy egy szál várjon egy eseményre.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool kesz = false;
void dolgozo() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return kesz; });
std::cout << "Munka elindult!" << std::endl;
}
void vezerlo() {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
kesz = true;
}
cv.notify_one();
}
int main() {
std::thread t1(dolgozo);
std::thread t2(vezerlo);
t1.join();
t2.join();
return 0;
}
Összegzés
Az std::thread lehetővé teszi több szál egyidejű futtatását, de figyelni kell a szinkronizációra és a versenyhelyzetekre. Az olyan eszközök, mint a mutex és a condition variable, segítenek a stabil programok megírásában.
- std::thread - Szótár.net (en-hu)
- std::thread - Sztaki (en-hu)
- std::thread - Merriam–Webster
- std::thread - Cambridge
- std::thread - WordNet
- std::thread - Яндекс (en-ru)
- std::thread - Google (en-hu)
- std::thread - Wikidata
- std::thread - Wikipédia (angol)