In the following program, during one thread (main) is performing thread::join
, another thread (x) calls thread::detach
:
#include <thread>
#include <iostream>
int main(void) {
auto t = std::thread([] {
std::this_thread::sleep_for( std::chrono::milliseconds(1000) );
} );
auto x = std::thread([&t] {
std::this_thread::sleep_for( std::chrono::milliseconds(500) );
if ( t.joinable() )
{
std::cout << "detaching t..." << std::endl;
t.detach();
}
} );
std::cout << "joining t..." << std::endl;
t.join();
x.join();
std::cout << "Ok" << std::endl;
return 0;
}
It work fine in GCC's libstdc
and Clang's libc
printing
joining t...
detaching t...
Ok
but in Visual Studio the program terminates with not-zero exit code before printing Ok
. Online demo: https://gcc.godbolt.org/z/v1nEfaP7a
Is it a bug in Visual Studio or the program contains some undefined behavior?
CodePudding user response:
Neither join
nor detach
are const
-qualified and therefore the implementation is allowed to modify internal memory of the thread
object without having to provide any guarantees of write/write or write/read data race avoidance on unsynchronized calls to these member functions per the default data race avoidance requirements of [res.on.data.races].
There is also no exception to this rule mentioned in [thread.threads] or anywhere else for these functions.
Therefore calling join
and detach
without establishing a happens-before relation between the two calls is a data race and causes undefined behavior.
Even without the detach
call, there is still a write/read data race on the join
/joinable
pair of calls.