我有一个日志系统,它基本上使用线程本地缓冲区来记录。这有助于减少锁定。可以将一堆消息写入线程本地缓冲区并一次性刷新。而且由于它是线程本地的,我们可以避免为每个日志消息分配缓冲区。
无论如何,问题是在进程退出期间。我们在访问线程本地缓冲区时看到崩溃。
我拥有的线程本地对象类似于std::vector<Buffer>
. [vector
因为有多个缓冲区]。代表性的代码是这样的。
Buffer* getBuffer (int index)
{
static thread_local auto buffers = std::make_unique<std::vector<Buffer>>();
return buffers ? buffers->at(index) : nullptr;
}
现在,当程序退出并调用全局析构函数时,不幸的是其中一些会记录。析构函数是从主线程调用的(否则不执行任何操作)。因此,当第一个全局对象被销毁并调用记录器时,会创建 thread_local 缓冲区,但它会立即被销毁,因为对象以与创建相反的顺序被销毁,并且这是创建的最后一个静态对象。当下一个全局对象析构函数调用记录器时,它正在有效地访问被破坏的对象,我认为这就是问题所在。
但我查看了 unique_ptr 析构函数,它确实将其内部的指针设置为 nullptr [或者至少将指针设置为默认构造的指针 - 我相信其值初始化为零??]。所以我的return buffers ? buffers->at(index) : nullptr;
检查应该阻止访问已释放的对象,不是吗?
我创建了一个玩具程序来尝试这个,我发现buffers ?
检查确实阻止了访问。但在真实的代码库中,这种情况并没有发生。在崩溃时,访问的向量已经是烤面包了。
现在,如果有人能告诉我一个神奇的解决方案,它会让我的生活变得轻松:-)。否则任何想法为什么bool
的运算符unique_ptr
不返回false
。是因为它是访问被破坏的对象的经典未定义行为吗?
我在堆栈溢出中读到,如果对象有一个简单的析构函数,则可以在销毁后访问它。在这种情况下,如果我创建一个线程本地的,我的问题就解决了bool
就在上面unique_ptr
,并在包含的包装类的析构函数中将其设置为 trueunique_ptr
?