Threads: why and how
A program executes its statements one at a time. While a function computes, the rest of the work waits, even when the processor has idle cores. To run two tasks at once, you need a second thread.
A thread is a sequence of statements that executes independently of the others. Every program has at least one thread, the one that runs main. The std::thread object from the <thread> header starts a new one:
#include <iostream>
#include <thread>
void print_squares() {
for (int i = 1; i <= 3; ++i) {
std::cout << i * i << ' '; // 1 4 9
}
}
int main() {
std::thread worker(print_squares);
worker.join();
std::cout << "done\n"; // done
}Starting and waiting
The std::thread constructor creates a thread and immediately starts print_squares in it. Meanwhile, main does not wait: the next line runs in the main thread alongside the new one. The call worker.join() stops main until the worker thread finishes. That is why done is always printed after the squares.
If main printed done before join(), the output of the two threads could mix. The order in which threads execute their statements is not defined.
The function's arguments go to the constructor after its name: std::thread t(f, 1, 2) calls f(1, 2) in the new thread. You can pass a lambda instead of a function, too. All threads of a program share its memory: a global variable is one and the same for all of them.
detach and jthread
Instead of join(), you can call detach(): the thread keeps running on its own, but you can no longer wait for it. That is risky. If such a thread reads local variables of the function that started it, it may access them after they are destroyed. That is undefined behavior.
C++20 added std::jthread. It is started the same way as std::thread, but the std::jthread destructor calls join() by itself. So you cannot forget to wait for such a thread.
Common mistake
The thread is started but never waited for:
int main() {
std::thread worker(print_squares);
std::cout << "done\n";
} // ✗terminate called without an active exceptionThe program builds without warnings. But on exit from main, the worker object is destroyed although neither join() nor detach() has been called on it. In that case the std::thread destructor calls std::terminate, and the program ends abnormally. Call join() before the end of the scope, or use std::jthread.