在仍然使用 boost 日志从其他线程记录日志的同时添加或删除日志接收器是否安全?

Is it safe to add or remove log sinks while still logging from other threads with boost log?

使用 boost::log 在仍然从其他线程记录日志的同时添加或删除日志接收器是否安全?我需要做一些手动锁定以使这些操作线程安全吗?

我想做的是启动一个新的文本文件,其中包含我程序中两点之间现有日志文件条目的子集。

例如,如果我将以下条目转到日志文件 "main_debug.log"

line 1
line 2
line 3
line 4

然后我在第 1 行之后添加一个新接收器,并在第 3 行之后删除它,我会看到 "new_debug.log" 包含以下条目

line 2
line 3

我所拥有的似乎大部分时间都在工作,但我偶尔会看到 boost::log 中发生分段错误。当我设法用 gdb 捕获它时发生的一个例子:

Program received signal SIGSEGV, Segmentation fault.
[Switching to LWP 8760]
boost::intrusive::list_impl<boost::intrusive::derivation_value_traits<boost::log::v2_mt_posix::attribute_value_set::node, boost::log::v2_mt_posix::attribute_value_set::implementation::node_traits, (boost::intrusive::link_mode_type)0>, unsigned int, true, void>::clear_and_dispose<boost::log::v2_mt_posix::attribute_value_set::implementation::disposer> (this=0x5e64aff4, disposer=...) at /boost-1.60.0/boost/intrusive/list.hpp:738
738     /boost-1.60.0/boost/intrusive/list.hpp: No such file or directory.
(gdb) bt
#0  boost::intrusive::list_impl<boost::intrusive::derivation_value_traits<boost::log::v2_mt_posix::attribute_value_set::node, boost::log::v2_mt_posix::attribute_value_set::implementation::node_traits, (boost::intrusive::link_mode_type)0>, unsigned int, true, void>::clear_and_dispose<boost::log::v2_mt_posix::attribute_value_set::implementation::disposer> (this=0x5e64aff4, disposer=...) at /boost-1.60.0/boost/intrusive/list.hpp:738
#1  boost::log::v2_mt_posix::attribute_value_set::implementation::~implementation (this=0x5e64afe8, __in_chrg=<optimized out>) at /boost-1.60.0/libs/log/src/attribute_value_set.cpp:150
#2  boost::log::v2_mt_posix::attribute_value_set::implementation::destroy (p=0x5e64afe8) at /boost-1.60.0/libs/log/src/attribute_value_set.cpp:239
#3  boost::log::v2_mt_posix::attribute_value_set::~attribute_value_set (this=0x5e64b3e4, __in_chrg=<optimized out>) at /boost-1.60.0/libs/log/src/attribute_value_set.cpp:519
#4  0x76e3bbac in boost::log::v2_mt_posix::record_view::public_data::~public_data (this=0x5e64b3e0, __in_chrg=<optimized out>) at /boost-1.60.0/boost/log/core/record_view.hpp:86
#5  boost::log::v2_mt_posix::record_view::private_data::~private_data (this=0x5e64b3e0, __in_chrg=<optimized out>) at /boost-1.60.0/libs/log/src/core.cpp:79
#6  boost::log::v2_mt_posix::record_view::private_data::destroy (this=0x5e64b3e0) at /boost-1.60.0/libs/log/src/core.cpp:131
#7  boost::log::v2_mt_posix::record_view::public_data::destroy (p=0x5e64b3e0) at /boost-1.60.0/libs/log/src/core.cpp:184
#8  0x0020b030 in boost::log::v2_mt_posix::sinks::asynchronous_sink<boost::log::v2_mt_posix::sinks::text_file_backend, boost::log::v2_mt_posix::sinks::unbounded_fifo_queue>::run() ()
#9  0x76d4be6c in boost::(anonymous namespace)::thread_proxy (param=<optimized out>) at /boost-1.60.0/libs/thread/src/pthread/thread.cpp:167
#10 0x76c22f00 in ?? () from /lib/libpthread.so.0

要添加新的接收器,我正在执行以下操作:

const auto pDebugBackend = boost::make_shared<boost::log::sinks::text_file_backend>(
    boost::log::keywords::file_name = "debug.log",
    boost::log::keywords::channel = "InfoConsole" );
const auto pNewDebugSink = boost::make_shared<boost::log::sinks::asynchronous_sink<boost::log::sinks::text_file_backend>>( pDebugBackend );

// Other code to set the filter and formatter for the sink.

boost::log::core::get()->add_sink( pNewDebugSink );

稍后我会移除水槽,这遵循 https://www.boost.org/doc/libs/1_60_0/libs/log/doc/html/log/detailed/sink_frontends.html#log.detailed.sink_frontends.async:

中描述的顺序
boost::log::core::get()->remove_sink( pNewDebugSink );
pNewDebugSink->stop();
pNewDebugSink->flush();
pNewDebugSink.reset();

我正在使用 boost-1.60.0,它是在启用线程支持的情况下构建的。

With boost::log is it safe to add or remove log sinks while still logging from other threads?

是的,尽管添加和删除接收器是两个不同的操作,并且在删除旧接收器而尚未添加新接收器时,您可能会遗漏一些日志记录。

关于您看到的崩溃,它似乎是在专用日志记录线程仍处于 运行 时发生的(即在 stop 方法完成之前),因此有可能删除接收器没有关系。这可能是 Boost.Log 或它使用的其他库中的错误,但您的 Boost 版本相当旧。尝试更新,如果它仍然可以重现,report a bug 在 Boost.Log 中使用重现器代码示例。