Как я могу синхронизировать - делать атомарные записи в одном файле из двух процессов?
======================================================================================

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

процесс 1 буфер записи A включает в себя (A1, A2, A3) и буфер B записи процесса 2, включая (B1, B2, B3). когда мы используем системный вызов `write()` для записи этих буферов на диск в один и тот же файл (весь буфер за один раз: `write(fd, A, sizeof(A))`). Как файловая схема?

* Это так: A, B или B, может быть?
* или это может быть так: A1, A2, B1, A3,...

Я спрашиваю об этом, потому что системные вызовы являются атомарными. что произойдет, если буфер данных, который мы пишем, слишком велик. Это как трубы для обычных файлов на диске?

 

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

Каждый вызов `write` будет записываться в число запрошенных байтов. Если ваш процесс прерывается сигналом, вы можете получить частичную запись - возвращается фактическое количество записанных байтов. Получаете ли вы все свои байты или нет, вы написали один смежный раздел файла. Вы не получаете эффект перемежения, который вы упомянули, как свою вторую возможность (например, A1, B1, A2, B2,...).

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

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

 

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

Системный вызов записи является атомарным, да, это означает, что результатом будет либо A, либо B, а не смесь обоих.

Предполагая, что вы хотите как A, так и B в файле, вы можете открыть файл с помощью O\_APPEND; обратите внимание, что это не будет работать над NFS.

Другим вариантом является то, что каждый процесс отслеживает, какое смещение файла он должен использовать, и использует lseek() или pwrite()

 

Вам определенно нужна какая-то форма синхронизации для ваших программ, которые обращаются к файлу, или вы получаете испорченное содержимое файла. Системный вызов `write` может писать меньше байтов, чем вы запросили, поэтому ваши блоки A1, A2 или B1, B2 могут быть записаны только частично. Это может происходить часто или редко, в зависимости от многих условий. Если это происходит только один раз в неделю, у вас будет ошибка, которая может быть очень трудно обнаружить.

В качестве решения вы можете использовать блокировку файлов (`man 2 flock` или `man fcntl` и поиск блокировки). Другая возможность заключается в использовании семафоров (`man -k semaphore`) для синхронизации ваших программных записей или некоторых других форм IPC.