Безопасно ли добавлять или удалять приемники журналов, продолжая вести журнал из других потоков с журналом повышения?

С 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, и он построен с включенной поддержкой многопоточности.


person Ian Gralinski    schedule 09.04.2020    source источник


Ответы (1)


С boost::log безопасно ли добавлять или удалять приемники журналов, продолжая вести журнал из других потоков?

Да, хотя добавление и удаление приемника — это две разные операции, и вы можете пропустить некоторые записи журнала, пока старый приемник удален, а новый еще не добавлен.

Что касается сбоев, которые вы видите, кажется, что это происходит, когда выделенный поток ведения журнала все еще работает (т. е. до завершения метода stop), поэтому возможно, что удаление приемника не связано. Это может быть ошибка в Boost.Log или какой-то другой используемой им библиотеке, но ваша версия Boost довольно старая. Попробуйте обновить, и если он все еще воспроизводится, сообщите об ошибке в Boost.Log с образцом кода воспроизводящего устройства. .

person Andrey Semashev    schedule 09.04.2020
comment
Проблема возникает на встроенной платформе, где я не могу легко обновить boost из-за ряда других зависимостей, которые также зависят от этой версии boost. Я посмотрю, смогу ли я создать небольшой образец, воспроизводящий проблему; пока не повезло. - person Ian Gralinski; 09.04.2020