Ant*_*res 11 c++ multithreading mingw mingw-w64 c++11
我有一个程序,用于thread_local std::shared_ptr管理一些主要在本地线程访问的对象。但是,当线程加入并且线程局部shared_ptr正在析构时,如果程序是由MinGW(Windows 10)编译的,那么在调试时总是会出现SIGSEGV。以下是重现该错误的最少代码:
// main.cpp
#include <memory>
#include <thread>
void f() {
thread_local std::shared_ptr<int> ptr = std::make_shared<int>(0);
}
int main() {
std::thread th(f);
th.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如何编译:
g++ main.cpp -o build\main.exe -std=c++17
Run Code Online (Sandbox Code Playgroud)
编译器版本:
>g++ --version
g++ (x86_64-posix-seh-rev2, Built by MinGW-W64 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)
使用 gdb 运行,当主线程等待时,它会在新线程中给出 SIGSEGV join()。当由 gcc、clang (Linux) 和 MSVC (Windows) 编译时,它工作正常。
我尝试调试发现,0xfeeefeee在调用RtlpWow64SetContextOnAmd64. 框架:
RtlpWow64SetContextOnAmd64 0x00007ffd8f4deb5f
RtlpWow64SetContextOnAmd64 0x00007ffd8f4de978
SbSelectProcedure 0x00007ffd8f4ae2e0
CloseHandle 0x00007ffd8ce3655b
pthread_create_wrapper 0x00007ffd73934bac
_beginthreadex 0x00007ffd8e9baf5a
_endthreadex 0x00007ffd8e9bb02c
BaseThreadInitThunk 0x00007ffd8ec87614
RtlUserThreadStart 0x00007ffd8f4c26a1
Run Code Online (Sandbox Code Playgroud)
大会:
...
mov %rax,(%rdi)
movdqu %xmm0,(%rsi) ; <------ erased here
call 0x7ffd8f491920 ; <ntdll!RtlReleaseSRWLockShared>
mov $0x1,%r9d
mov 0x30(%rsp),%rbx
...
Run Code Online (Sandbox Code Playgroud)
后来shared_ptr被破坏,读取时0xfeeefeee有SIGSEGV。
我想知道:
join()替换为detach(),则程序正常退出。也许join()做了一些事情来指示新线程擦除存储?这是 mingw 中长期存在的、开放的已知错误,请参阅 github 上的相应问题及其分析和链接: https: //github.com/msys2/MINGW-packages/issues/2519
是的,这违反了标准:它不应该崩溃。基本上,正如您已经怀疑的那样,破坏顺序是不正确的。这是用于标记已释放内存的0xfeeefeee幻数。HeapFree()参见例如这篇文章。
引用lhmouse:
因此,经验法则是:不要在 GCC 上为 MinGW 目标使用 thread_local。