Безопасно иметь несколько процессов пишут в один и тот же файл одновременно? [В CentOS 6, в ext4]

Я создаю систему, в которой несколько подчиненных процессов взаимодействуют через доменные сокеты unix, и они пишут в тот же файл в то же время. Я никогда не изучал файловые системы или эту конкретную файловую систему (ext4), но кажется, что здесь может быть какая-то опасность.

каждый процесс записывает в непересекающееся подмножество выходного файла (т. е. в записываемых блоках нет перекрытия). Например, P1 записывает только первые 50% файла и P2 записывает только до вторых 50%. Или, может быть,P1 пишет только нечетные блоки, в то время как P2 записывает четные блоки.

безопасно ли есть P1 и P2 (выполняется одновременно в отдельных потоках) запись в один и тот же файл без использования блокировки? Другими словами, неявно ли файловая система накладывает какую-то блокировку?

Примечание: к сожалению, я не могу выводить несколько файлов и присоединяться к ним позже.

Примечание: мое чтение с момента публикации этого вопроса не согласуется с единственным опубликованным ответом ниже. Все, что я читал, говорит о том, что я хочу делать хорошо, в то время как респондент ниже настаивает на том, что я делаю небезопасно, но я не могу различить описанную опасность.

2 ответов


то, что вы делаете, кажется совершенно нормальным, если вы используете POSIX "raw" IO syscalls, такие как read (), write (), lseek() и так далее.

Если вы используете c stdio (fread (), fwrite () и friends) или какую-либо другую библиотеку языковой среды выполнения, которая имеет свою собственную буферизацию пользовательского пространства, то ответ "Tilo" релевантен, в том, что из-за буферизации, которая в некоторой степени находится вне вашего контроля, различные процессы могут перезаписывать данные друг друга.

блокировка ОС Wrt, в то время как POSIX утверждает, что запись или чтение меньше размера PIPE_BUF являются атомарными для некоторых специальных файлов (труб и FIFO), нет такой гарантии для обычных файлов. На практике я думаю, что, скорее всего, IO внутри страницы являются атомарными, но такой гарантии нет. ОС выполняет внутреннюю блокировку только в той мере, в какой это необходимо для защиты собственных внутренних структур данных. Для сериализации доступа к файлам можно использовать блокировки файлов или какой-либо другой механизм межпроцессной связи. Но, все это относится только к вам, у вас есть несколько процессов, выполняющих ввод-вывод в одну и ту же область файла. В вашем случае, поскольку ваши процессы делают IO для разъединения разделов файла, ничто из этого не имеет значения, и вы должны быть в порядке.


нет, как правило, это небезопасно делать!

вам нужно получить монопольную блокировку записи для каждого процесса-это означает, что все остальные процессы будут ждать, пока один процесс пишет в файл.. чем больше интенсивных процессов ввода-вывода, тем дольше время ожидания.

лучше иметь один выходной файл для каждого процесса и форматировать эти файлы с меткой времени и идентификатором процесса в начале строки, чтобы вы могли позже объединить и отсортировать эти выходные файлы в автономном режиме.

совет: проверьте формат файла файлов журнала веб-сервера - они сделаны с отметкой времени в начале строки, поэтому они могут быть позже объединены и отсортированы.


редактировать

процессы UNIX используют определенный / фиксированный размер буфера при открытии файлов (например, 4096 байт) для передачи данных в файл на диске и из него. Как только буфер записи заполнен, процесс сбрасывает его на диск - это означает: он пишет полный полный буфер на диск! Обратите внимание, что это происходит, когда буфер полон! -- нет, когда есть конец линии! Это означает, что даже для одного процесса, который записывает в файл текстовые данные, ориентированные на строки, эти строки обычно вырезаются где-то посередине во время сброса буфера. Только в конце, когда файл закрывается после записи, можно предположить, что файл содержит полные строки!

Так в зависимости от когда ваш процесс решит потопить их буферы, они пишут в разное время в файл - например, порядок не является детерминированным / предсказуемым, когда буфер сбрасывается в файл, вы можете Не предполагайте, что он будет писать только полные строки -- например,обычно он будет писать частичные строки, тем самым испортив выход, если несколько процессов очищают свои буферы без синхронизации.

проверьте эту статью в Википедии: http://en.wikipedia.org/wiki/File_locking#File_locking_in_UNIX

цитата:

операционные системы Unix (включая Linux и Mac OS X от Apple, иногда называют Дарвином)обычно не автоматически блокировать открытые файлы или запуск программ. несколько видов файл-фиксируя механизмов доступно в различных вариантах Unix и во многих операционных системах поддержите больше чем один вид для совместимость. Два наиболее распространенных механизмы-fcntl (2) и flock(2). Третий такой механизм lockf (3), который может быть отдельным или может быть реализован с использованием первые два примитива.

вы должны использовать flock, или мьютексы синхронизировать процессы и убедитесь, что только один из них может писать в файл одновременно.

Как я уже упоминал ранее, вероятно, быстрее, проще и более прямолинейно иметь один выходной файл для каждого процесса, а затем при необходимости объединить эти файлы (в автономном режиме). этот подход используется некоторыми веб-серверами, например, которым необходимо войти в несколько файлов из нескольких потоков - и нужно убедиться, что все разные потоки являются высокопроизводительными (например, не нужно ждать друг друга на блокировке файла).


вот связанный пост: (отметьте ответ Байера! принятый ответ не является правильным/уместным.)

это безопасно передавать вывод нескольких параллельных процессов в один файл с помощью >>?


EDIT 2:

в комментарии Вы сказали, что хотите записать двоичные блоки данных фиксированного размера из разных процессов в один и тот же файл.

только в том случае, если размер вашего блока точно соответствует размеру файла-буфера системы, это может работать!

убедитесь, что ваша фиксированная длина блока является именно файловым буфером системы размер. В противном случае вы попадете в ту же ситуацию, что и с незавершенными строками. например, если вы используете 16K блоков, а система использует 4K блоков, то в целом вы увидите 4K блоков в файле в кажущемся случайном порядке - нет никакой гарантии, что вы всегда будете видеть 4 блока подряд из одного и того же процесса