имхо по-уму система логгирования (так же как и система генерации дампов и прочие неубиваемые сервисы) должна висеть в отдельном процессе.
Sayron
> Конишуа, а обычное STL'овское write скидывает данные в буффер ядра или пишет
> прямо на диск
Iostream-ы открывают файл в режиме буферизации в ядре.
Кроме того, в самом объекте stream есть буфер.
То есть данные сначала попадают в пользовательский буфер, откуда отсылаются в ядро по достижению некоторой критической массы.
А ядро физически запишет данные на диск когда ему будет это удобно.
Чтобы сбросить пользовательский буфер в stream-е есть метод flush.
Также сброс буфера происходит при выводе в поток объекта std::endl.
Stdio в части буферизации полностью идентична.
Sayron
> Чем плохо скидывание в системный буффер строк из нескольких потоков
> одновременно?
Внутри стрима нет синхронизации, все упадет.
Кстати олдскульный FILE можно безопасно использовать из нескольких тредов одновременно.
Edit: поправил тэги.
Sayron
> Сейчас скину свою реализацию, которая НЕ РАБОТАЕТ при падении программы.
Добавь flush после write.
JokerR, поясните свою мысль пожалуйста.
Как вести логи в мультипотоковом приложении.
Вот допустим я имею несколько потоков
1 - поток для рендера
2 - поток обсчета Аи
3 - под музыку
Как при этом (в общих чертах) ведутся логи?
Sayron
> Как при этом (в общих чертах) ведутся логи?
В разные файлы?
Нет-нет... Просто допустим как должен блок АИ формировать логи (куда писать) если потоки параллельны?
Щас я кратко постараюсь написать как я собираюсь делать двиг мультипотоковым.
Значит есть у нас 3 потока -
1 - Поток для создания того, что будет отправляться в видеопамять.
2 - обсчет АИ по данным.
3 - поток под музыку.
1 и 3-ий потоки используют данные, подготовленные вторым потоком.
Во время критической секции у нас происходит следующее.
АИ-поток формирует буфер данных для потоков 1 и 3 (делает снимок необходимых данных).
Соответственно во время параллельного выполнения ни один поток не лезет к другому в память.
Вот мне и интересно - каким образом формировать поток логов?
Sayron
> Во время критической секции у нас происходит следующее.
Если тебе знаком термин критическая секция, почему возникают вопросы как синхронизировать доступ к логу из нескольких параллельных тредов?
Допустим во время параллельного исполнения блок АИ падает. Как при этом сохранить логи?
Мне термин известен в теории...
На этой неделе у меня сверхзадача - доделать генератор карт (и я его походу доделаю).
Следующей стадией стоит задача сделать свой однопотоковый движок мультипотоковым (на основе директив openMP), поскольку игра будет представлять собой варгейм аля Европа 3 и на обсчет АИ там хватит только нескольких реальных секунд. Поскольку АИ будет довольно таки сложным (и делаться на основе обсчетов векторов STL), то вылеты во время отладки неизбежны.
А поскольку я свой генератор карты делаю уже почти год (и знаю, что у меня в коде бывают как тупые ошибки, так и очень-очень глубоко зарытые, всплывающие раз в месяц под знаком всемогущего рандома), то требуется вести отладку логами.
Как ты понимаешь - сохранение логов при этом глобальная задача, резко ускоряющая отладку кода и работу над проектом в целом.
Sayron
> Допустим во время параллельного исполнения блок АИ падает. Как при этом
> сохранить логи?
Технически это выглядит как-то так.
Тред, в котором исполнялся упавший код ловит необработанное исключение в UnhandledExceptionFilter.
В это время другие треды продолжают работать.
Фильтр входит в критическую секцию, которая охраняет лог (потому что другие треды продолжают работать).
Сбрасываются все буферизованные строки.
После этого фильтр возвращает EXCEPTION_CONTINUE_SEARCH, что приводит к появлению стандартного окна с предложением отправить отчет в Microsoft или подключить отладчик, и в конечном счете, к завершению процесса.
Какие тут есть подводные камни?
Последнее совсем уж маловероятно, потому что стандартная логика в случае необработанного исключения - "пострадаваший" процесс сам запускает новый процесс, который и показывает окно с предложением отправить отчет.
Все это маловероятно, но теоретически возможно.
Я бы не пытался оптимизировать до тех пор, пока все не упрется в производительность лога, и сделал бы попроще.
Одна запись в логе - один вызов ядра, нет необходимости сбрасывать буфера при сбое.
Делал бы тупо через stdio (потому что вызовы из разных тредов автоматически синхронизируются).
Конишуа
То есть, по сути ты предлагаешь сделать следующим образом. В общем виде:
У каждого потока есть свой лог-файл, в который они сбрасывают данные. Как только поток дал сбой - stdio как я понимаю, ВСЕ открытые через него файлы закрывает, и мы сохраняем логи на момент падения потока.
Таким образом никакого отдельного потока под логи нет, а система сброса данных записи в ядро все синхронизирует сама (то есть если один поток скидывает данные в свой файл одновременно с другим, то все будет нормально и библиотека stdio, т.о. потокобезопасна? )
Sayron
Да нет же.
Есть объект, один на все приложение, через который пишутся логи.
Как пример - тупо FILE из stdio.
Библиотека stdio синхронизует доступ к своим объектам из нескольких тредов одновременно.
С каждым объектом FILE связана своя критическая секция (КС).
Каждый метод, например fprintf(), захватывает эту КС на время своей работы.
Таким образом, можно без проблем вызывать fprintf() из разных тредов над одним и тем же объектом FILE.
В отличие от std::ostream, для которой потокобезопасность не гарантируется.
То есть лог файл - он один, на все треды.
Идем дальше.
У объекта FILE есть свой собственный буфер, который находится в памяти приложения.
Данные в нем накапливаются, а затем доставляются в ядро ОС системным вызовом write (Linux) или WriteFile (Win).
Так вот, этот буфер надо сбрасывать в момент сбоя.
Я предлагаю сбрасывать буфер после каждой записи в лог (функцией fflush или как-то еще).
Тем самым, гарантируется что в момент сбоя буфер пуст, и ничего делать не надо.
И если потом окажется что частый fflush() тормозит (не верю), можно будет перенести fflush() в обработчик неперехваченных исключений (установленный SetUnhandledExceptionFilter).
Ну все - наконец-то дошло!
Огромное спасибо за проявленное старание во вдалбливание материала в мою не С-шную голову!!!
Буду пробовать
Тема в архиве.