我有一个日志系统,基本上使用线程本地缓冲区进行记录。这有助于减少锁定。一堆消息可以写入线程本地缓冲区并在一次刷新中刷新。而且由于它是线程本地的,我们可以避免为每个日志消息分配缓冲区。
无论如何,在进程退出过程中出现问题。我们在访问线程本地缓冲区时看到崩溃。
我拥有的线程本地对象类似于
现在当程序退出并调用全局析构函数时,不幸的是其中一些会记录日志。析构函数从主线程调用(否则什么也不做)。因此,当第一个全局对象被销毁并调用记录器时,线程本地缓冲区被创建,但立即被销毁,因为对象按创建顺序的相反顺序销毁,并且这是最后创建的静态对象。当下一个全局对象析构函数调用记录器时,它实际上正在访问已销毁的对象,我认为这就是问题所在。
但是我查看了unique_ptr析构函数,它确实将其内部指针设置为nullptr [或者至少将指针设置为默认构造的指针-我相信这是值初始化为零吗?]。所以我的
我创建了一个玩具程序来尝试这个问题,我发现
现在如果有人告诉我一个神奇的解决方案,那将使我的生活变得容易:-)。否则,有没有人知道为什么
我在stackoverflow上读到,如果对象具有平凡的析构函数,则在销毁后访问它是可以的。在那种情况下,如果我在包含
无论如何,在进程退出过程中出现问题。我们在访问线程本地缓冲区时看到崩溃。
我拥有的线程本地对象类似于
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;
}
现在当程序退出并调用全局析构函数时,不幸的是其中一些会记录日志。析构函数从主线程调用(否则什么也不做)。因此,当第一个全局对象被销毁并调用记录器时,线程本地缓冲区被创建,但立即被销毁,因为对象按创建顺序的相反顺序销毁,并且这是最后创建的静态对象。当下一个全局对象析构函数调用记录器时,它实际上正在访问已销毁的对象,我认为这就是问题所在。
但是我查看了unique_ptr析构函数,它确实将其内部指针设置为nullptr [或者至少将指针设置为默认构造的指针-我相信这是值初始化为零吗?]。所以我的
return buffers ? buffers->at(index) : nullptr;
检查应该已经防止了对已释放对象的访问,不是吗?我创建了一个玩具程序来尝试这个问题,我发现
buffers ?
检查确实可以防止访问。但是在真正的代码库中,这种情况并没有发生。在崩溃点处,向量已经被访问并且已经失效。现在如果有人告诉我一个神奇的解决方案,那将使我的生活变得容易:-)。否则,有没有人知道为什么
unique_ptr
的bool
运算符不返回false
。这是因为访问已销毁的对象是典型的未定义行为吗?我在stackoverflow上读到,如果对象具有平凡的析构函数,则在销毁后访问它是可以的。在那种情况下,如果我在包含
unique_ptr
的包装器类的析构函数中创建一个线程本地的bool
,并将其设置为true,那么我的问题是否解决了?
main
之前进行清理,因为你可以使用显式代码更好地控制。 - Phil1970main()
退出后执行。最好在main
函数中完成这个操作。在main
中创建一个日志对象,然后将其传递给需要记录日志的任何对象。 - Martin York