Как я могу синхронизировать - сделать атомарный - запись в один файл из двух процессов?
У меня есть два процесса, каждый из которых записывает большой буфер данных, и я хочу контролировать синхронизацию записи этих процессов в один файл.
буфер записи процесса 1, включающий (A1, A2, A3), и буфер записи процесса 2, включающий (B1, B2, B3). когда мы используем write()
системный вызов для записи этих буферов на диск в один и тот же файл (весь буфер за один раз: write(fd, A, sizeof(A))
) Как схема файла?
- Это так: A, B или B, A возможно?
- или это может быть так: A1, A2, B1, A3, ...
Я спрашиваю об этом, потому что системные вызовы являются атомарными. что произойдет, если буфер данных, который мы пишем, слишком велик. Это как трубы для обычных файлов на диске?
3 ответа
Если вы хотите, чтобы содержимое обоих буферов присутствовало, вы должны открыть файлы с O_APPEND
флаг установлен. Флаг добавления ищет конец файла перед записью. Без этого набора возможно, что оба процесса будут указывать на одни и те же или перекрывающиеся области файла, и тот, кто пишет в последний раз, будет перезаписывать то, что написал другой.
Каждый звонок write
запишет до количества запрошенных байтов. Если ваш процесс прерывается сигналом, то вы можете получить частичную запись - возвращается реальное количество записанных байтов. Независимо от того, записали ли вы все свои байты или нет, вы запишете один непрерывный раздел файла. Вы не получите эффект чередования, который вы упомянули в качестве второй возможности (например, A1,B1,A2,B2,...).
Если вы получите только частичную запись, то, как вы поступите, зависит от вас. Вы можете либо продолжить запись (смещение от начала буфера на количество ранее записанных байтов), либо вы можете отказаться от оставшейся части записи. Только так вы можете получить эффект чередования.
Если важно, чтобы содержимое одной записи было завершено до того, как другой процесс выполнит запись, то вам следует изучить блокировку файла для монопольного доступа к записи (который должен проверить оба процесса), прежде чем пытаться записать какие-либо данные.
Вам определенно нужна какая-то форма синхронизации для ваших программ, которые обращаются к файлу, или вы в итоге испортили содержимое файла. write
Системный вызов может записать меньше байтов, чем вы запрашивали, поэтому ваши блоки A1, A2 или B1, B2 могут быть записаны только частично. Это может происходить часто или редко, в зависимости от многих условий. Если это происходит только один раз в неделю, у вас будет ошибка, которую очень трудно обнаружить.
В качестве решения вы можете использовать блокировку файлов (man 2 flock
или же man fcntl
и поиск блокировки). Другая возможность заключается в использовании семафоров (man -k semaphore
) синхронизировать ваши записи программ или некоторые другие формы IPC.
Предполагая, что буферы имеют одинаковый размер, результат будет либо A, либо B, в зависимости от того, какой процесс был запланирован последним.
Да, системный вызов write является атомарным, это означает, что результатом будет либо A, либо B, а не смесь обоих.
Предполагая, что вы хотите, чтобы и A и B в файле, вы можете открыть файл с помощью O_APPEND; обратите внимание, что это не будет работать над NFS, хотя.
Другой вариант заключается в том, что каждый процесс отслеживает, какое смещение файла он должен использовать, и использует lseek() или pwrite().