Является ли реализация fprintf() в glibc поточно-ориентированной?
Является ли fprintf поточно-ориентированным? Руководство glibc, похоже, говорит, что это так, но мое приложение, которое записывает в файл с помощью одного вызова fprintf(), похоже, смешивает частичные записи из разных процессов.
редактировать: чтобы уточнить, рассматриваемая программа является плагином lighttpd, а сервер работает с несколькими рабочими потоками.
Глядя на файл, некоторые записи перемешаны.
edit 2: Кажется, проблема, которую я вижу, может быть связана с тем, что "рабочие потоки" lighttpd на самом деле являются отдельными процессами: http://redmine.lighttpd.net/wiki/lighttpd/Docs:MultiProcessor
Проблемы
Запустив 2 или более процессов в одном сокете, вы получите лучший параллелизм, но у вас будет несколько недостатков, о которых вы должны знать:
- mod_accesslog может создать поврежденные журналы доступа, так как один и тот же файл открывается дважды и НЕ синхронизируется.
- mod_status будет иметь n отдельных счетчиков, по одному для каждого процесса.
- mod_rrdtool завершится с ошибкой, поскольку он получает одну и ту же метку времени дважды.
- mod_uploadprogress не будет показывать правильный статус.
3 ответа
Вы путаете две концепции - запись из нескольких потоков и запись из нескольких процессов.
Внутри процесса можно гарантировать, что один вызов fprintf завершен до того, как следующему будет разрешен доступ к выходному буферу, но как только ваше приложение накачает этот вывод в файл, вы окажетесь во власти ОС. Без какого-либо механизма блокировки на основе ОС вы не сможете гарантировать, что совершенно другое приложение не запишет в ваш файл журнала.
Похоже, мне нужно читать о блокировке файлов. Проблема в том, что несколько процессов (т.е. не потоков) записывают в один и тот же файл одновременно, и нет надежного способа гарантировать, что записи будут атомарными. Это может привести к тому, что файлы перезаписывают записи друг друга, смешанный вывод и вообще недетерминированное поведение.
Это не имеет ничего общего с безопасностью потоков, поскольку это относится только к однопроцессным многопоточным программам.
Текущий стандарт C++ не говорит ничего полезного о параллелизме, равно как и стандарт C 1990 года. (Я не читал стандарт C 1999 года, поэтому не могу его комментировать; будущий стандарт C++0x говорит о многом, но я не знаю точно, что это за руки.)
Это означает, что сам fprintf(), вероятно, не является ни потокобезопасным, ни каким-либо иным образом, и что это будет зависеть от реализации. Я прочитал в точности то, что говорится в документации glibc, и сравнил это с тем, что вы делаете.