I was reading some manuals about threads and I've come to a thought that the code they show is not safe:
std::cout << "starting first helper...\n";
std::thread helper1(foo);
std::cout << "starting second helper...\n";
std::thread helper2(bar);
std::cout << "waiting for helpers to finish..." << std::endl;
helper1.join(); // #1 NOT SAFE
helper2.join(); // #2 NOT SAFE
I believe this code is not absolutely safe. If I am not mistaking there is no guarantee that helper1
and helper2
are already in joinable state when control reaches lines marked as #1
and #2
. Threads could still be not launched and have no ids at this point. Which will cause an uncaught exception being thrown from std::thread::join()
I think the following code fixes the problem. Am I right?
std::cout << "starting first helper...\n";
std::thread helper1(foo);
std::cout << "starting second helper...\n";
std::thread helper2(bar);
std::cout << "waiting for helpers to finish..." << std::endl;
while ( helper1.joinable() == false ) { }
helper1.join(); // #1 SAFE
while ( helper2.joinable() == false ) { }
helper2.join(); // #2 SAFE
A std::thread
is joinable
if it contains a thread state that has not been join
ed or detatch
ed.
A std::thread
gains a thread state by being non default constructed, or having one move
ed into it from another std::thread
. It loses it when move
ed from.
There is no delay in gaining the thread state after construction completes. And it does not go away when the threaded function finishes. So there is not that problem.
There is the problem that if code throws above, you will fail to join
or detatch
, leading to bad news at program shutdown. Always wrap std::thread
in a RAII wrapper to avoid that, or just use std::async
that returns void
and wrap the resulting std::future
similarly (because the standard says it blocks in the dtor, but microsofts implementation does not, so you cannot trust if it will or not).
You are perceiving threads in an overly complicated way. join
is there to safely join a thread. Just use:
std::thread my_thread(my_main);
my_thread.join();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With