我有一个程序,用于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 …
我最近使用了一个对象,其目的是将内存作为单例进行分配和释放。就像是
class MyValue
{
// ...
static Allocator& GetAllocator()
{
static Allocator allocator;
return allocator;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
后来我意识到它Allocator不是线程安全的:当多个线程同时使用同一个分配器时,偶尔会发生奇怪的事情,导致断言和分段错误。
解决方案:为不同的线程使用不同的分配器:
class MyValue
{
// ...
static Allocator& GetAllocator()
{
thread_local static Allocator allocator;
return allocator;
}
// ...
};
Run Code Online (Sandbox Code Playgroud)
惊人的!我的问题都消失了!只有一个问题: 每次创建线程时我的分配器变量都会被初始化,即使大多数线程不会使用该变量?
分配器的初始化可能是繁重的操作,因此我希望仅在实际需要时才对其进行初始化,而不是在每个线程中进行初始化。
我读到thread_local变量是由每个线程分配的。这是否意味着它们也是被构建的?这种分配(或构造)是针对创建的每个线程系统地发生还是仅针对使用它的线程发生?
我依稀记得在课程中听说过有关线程和线程本地存储的大多数细节都依赖于平台。如果是这样的话,我对 Linux 和 FreeBSD 特别感兴趣。
相关(有趣的读物,但我在那里找不到答案):
我有许多正在运行的C ++ 11线程,它们都需要在某个时间访问数据库。在主要方面,我会初始化数据库连接并打开数据库。Qt文档说查询不是线程安全的,因此在线程内部存在QSqlQuery之前,我将使用全局互斥锁。
这行得通,但是否可以保证正常工作,或者我有时会遇到问题?