Reputation: 9390
Anyone knows what kind of UB is this? The following code deadlocks on jthread
destruction when built with MSVC 19.29.30148, sometimes it deadlocks after std::cout and sometimes before.
This is somehow related to thread_local, but I cannot see what is the issue. It seems to work fine under other compilers and platforms.
#include <thread>
#include <memory>
#include <iostream>
int main(void)
{
std::thread t2(
[&] {
thread_local std::jthread asd([] {
std::cout << "ASD" << std::endl;
});
});
if (t2.joinable()) { t2.join(); }
}
Update: Reproducible both on static and dynamic runtime
Upvotes: 21
Views: 637
Reputation: 13073
Its difficult to describe this as a library bug.
What is happening.
thread_local std::thread asd
This is in a thread, creates a thread and stores it in thread local storage.
When thread t2
completes, it starts the thread destruction process. This process is naturally single threaded - 2 threads can't end at the same time, and they get serialized.
The threaded mechanisms note that there is thread_local
storage for that thread, and start calling the destructor for asd, which includes invoking the join
function.
So we wait for asd to be able to complete. Unfortunately it is unable to do this, as the thread destruction of asd
is blocked by the thread t2
- which is in progress. Hence the deadlock.
Fixes.
t2
's function.The library writers have a really difficult set of goals to achieve. They need to ensure that thread-local data is tidied up in a timely manner. If thread local destruction is delayed until after the thread is finished, referred to data which went out of scope with the thread, there would be bugs.
If they (as implemented), tidied up in the context where the thread is in the process of being destroyed, they face this form of inter-thread deadlock.
Update
Running on linux (wasn't sure what Clang and GCC meant apart from linux), I confirmed that the program as is,
asd
thread showed the destruction of thread_local asd
didn't slow or stop the destruction of thread-local-storage data (__GI__call_tls_dtors
)So I would say that the linux implementation has issues where a thread stored in thread_local
may refer to other thread_local
data which may be destroyed.
The use of thread_local
for asd
is completely unnecessary, and is the cause of the problem
Upvotes: -2