I have the following function:
void threadProc(){
for (int i = 0; i < 5; ++i) {
std::cout << "\n thread #" << std::this_thread::get_id() << " says hi";
}
std::cout << "\n Finished executing thread #" << std::this_thread::get_id();
}
And I am using it the following way:
int main(){
try {
std::thread t1(threadProc);
t1.join();
std::thread t2(threadProc);
HANDLE handle = t2.native_handle();
WaitForSingleObject(handle, INFINITE);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
std::cout << "\n thread t2 is joinable: " << std::boolalpha << t2.joinable() << "\n\n";
}
catch (std::exception& ex){
std::cout << "\n\n " << ex.what() << "\n\n";
}
return 0;
}
This is the output:
thread #21300 says hi
thread #21300 says hi
thread #21300 says hi
thread #21300 says hi
thread #21300 says hi
Finished executing thread #21300
thread #2136 says hi
thread #2136 says hi
thread #2136 says hi
thread #2136 says hi
thread #2136 says hi
Finished executing thread #2136
thread t2 is joinable: true
And then it crashes when the try block goes out of scope because abort()
was called on t2
.
My question is, why is t2
still joinable()
even when its threadProc
was over? Why did it not finish processing?
Moreover, I am using WaitForSingleObject
to ensure that I wait until t2
finishes processing. I also added the 5 seconds wait to make sure it takes its time to finish its processing. Yet something is still not done.
I know I can use t2.join()
or t2.detach()
but why do I have to? t2
has already finished processing (I think).
EDIT: I have tried the following code:
int main() {
try {
std::thread t1([]() {std::cout << "\n\n Hi from thread #" << std::this_thread::get_id(); });
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
catch (std::exception& ex) {
std::cout << "\n\n " << ex.what() << "\n\n";
}
return 0;
}
And still the thread is joinable. I looked up the joinable
reference and they say:
A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable.
So this isn't related to WaitForSingleObject
anymore. The question is why a thread is still considered joinable()
after it finished execution?
I have seen this question which confused me even more as it states that when the thread finished execution it was not joinable()
even before calling join()
or detach()
.
The question is why a thread is still considered joinable() after it finished execution?
Because you might want to write code that join()s it. If t.joinable()
automatically became false upon termination, then there would be no safe way to call t.join()
. You could write this:
if (t.joinable()) {
t.join();
}
But that still could throw an exception if the thread terminated after t.joinable()
had returned true
, but before the caller was able to complete the t.join()
call.
Having the thread remain joinable until it actually is join()ed is simpler behavior to describe, and it's easier to write code that uses it correctly.
joinable
doesn't mean still_running
, joinable simply means the thread object is not "empty" (as result of default construction or move) and is associated with a real OS-thread of execution.
if the thread is empty, that means there is nothing to join, hence, the thread is not "joinable".
if the thread is not empty, you can make the current thread wait for it, hence it is "joinable".
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