Асинхронный потокобезопасный вход в С++
Я ищу способ сделать асинхронное и потокобезопасное ведение журнала в моем проекте на С++, если возможно, одному файлу. В настоящее время я использую cerr
и clog
для задачи, но поскольку они являются синхронными, выполнение в кратчайшие сроки приостанавливается каждый раз, когда что-то записывается в журнал. Это относительно графическое приложение, поэтому такого рода вещи довольно раздражают.
Новый регистратор должен использовать асинхронный ввод-вывод, чтобы избавиться от этих пауз. Кроме того, было бы желательно обеспечить безопасность потоков, поскольку я намерен в ближайшее время добавить некоторые базовые многопоточности.
Я рассмотрел подход с одним файлом на поток, но похоже, что это приведет к тому, что управление журналами станет кошмаром. Любые предложения?
Ответы
Ответ 1
Я заметил эту 1 год + старую нить. Возможно, интересный асинхронный регистратор может представлять интерес.
http://www.codeproject.com/KB/library/g2log.aspx
G2log использует защищенную очередь сообщений для пересылки записей журналов фоновому работнику, к которому обращается медленный диск.
Я пробовал это с помощью незаблокированной очереди, которая увеличивала среднее время вызова LOG, но уменьшала наихудшее время, но теперь я использую защищенную очередь, поскольку она является кросс-платформенной. Он тестировался на Windows/Visual Studio 2010 и Ubuntu 11.10/gcc4.6.
Он выпущен как общедоступный домен, поэтому вы можете делать с ним то, что хотите, без привязки строк.
Ответ 2
Это ОЧЕНЬ возможно и практично. Откуда мне знать? Я написал именно это на моей последней работе. К сожалению (для нас), у них теперь есть код.:-) К сожалению, они даже не используют его.
Я намерен написать версию с открытым исходным кодом в ближайшем будущем. Между тем, я могу дать вам несколько советов.
- Манипуляторы ввода-вывода - это действительно просто имена функций. Вы можете реализовать их для своего собственного класса ведения журнала, чтобы ваш регистратор был совместим cout/cin.
- Ваши функции манипулятора могут токенизировать операции и хранить их в очереди.
- В этой очереди может быть заблокирован поток, ожидающий прохождения блоков журнала. Затем он обрабатывает операции с строкой и генерирует фактический журнал.
Это совместимо с потоками, поскольку вы используете очередь. Тем не менее, вы все равно захотите поместить некоторую защиту, подобную мьютексу, вокруг записи в очередь, чтобы данный журнал < "материал" < "больше вещей"; тип операции остается линейно-атомным.
Удачи!
Ответ 3
Рассматривали ли вы использование библиотеки журналов.
Есть несколько доступных, я недавно обнаружил Pantheios, и это действительно кажется невероятным.
Это больше входной регистратор, вы можете настроить, какая система используется. Он может взаимодействовать с ACE
или log4cxx
, например, и кажется очень простым в использовании и настройке. Главное преимущество заключается в том, что он использует типы операторов, которые всегда велики.
Если вы просто хотите использовать библиотеку протоколов barebone:
Выберите любой:)
Я должен отметить, что возможно реализовать блокировки в очереди на С++ и что они отлично подходят для ведения журнала.
Ответ 4
Я думаю, что правильный подход - это не один файл для потока, а одно-поток для каждого файла. Если какой-либо один файл (или ресурс в целом) в вашей системе доступен только по одному потоку, потоковое программирование становится намного проще.
Итак, почему бы не сделать Logger выделенным потоком (или несколькими потоками, по одному на файл, если вы регистрируете разные вещи в разных файлах), и во всех других потоках запись в журнал помещает сообщение во входную очередь в соответствующий поток Logger, который достигнет его после его записи предыдущего сообщения. Все, что требуется, - это мьютекс, чтобы защитить очередь от добавления события, пока Logger читает событие, и condvar для Logger ждет, когда его очередь пуста.
Ответ 5
У меня была такая же проблема, и я считаю, что нашел идеальное решение. Я представляю вам библиотеку с одним заголовком, называемую loguru: https://github.com/emilk/loguru
Он прост в использовании, переносится, настраивается, на основе макросов и по умолчанию не #include
ничего (для этого сладкого, сладкого времени компиляции).