Что происходит, если системный вызов write вызывается для одного файла двумя разными процессами одновременно - PullRequest
3 голосов
/ 30 августа 2011

Правильно ли работает ОС?

Или мне придется вызывать flock ()?

Ответы [ 5 ]

10 голосов
/ 30 августа 2011

Хотя ОС не будет аварийно завершать работу и файловая система не будет повреждена, вызовы write() НЕ гарантированы как атомарные, если рассматриваемый файловый дескриптор не является каналом, а объем записываемых данных составляет PIPE_MAX байта или меньше. Соответствующая часть стандарт :

Попытка записи в канал или FIFO имеет несколько основных характеристик:

  • Атомный / неатомарный: запись является атомарной, если все количество, записанное в одной операции, не чередуется с данными из любого другого процесса. Это полезно, когда несколько писателей отправляют данные одному читателю. Приложения должны знать, насколько большой запрос на запись может быть выполнен атомарно. Этот максимум называется {PIPE_BUF}. Этот том стандарта IEEE Std 1003.1-2001 не говорит о том, являются ли запросы записи для более чем {PIPE_BUF} байтов атомарными, но требует, чтобы записи {PIPE_BUF} или менее байтов были атомарными.

[...]

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

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

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

2 голосов
/ 30 августа 2011

writewritev тоже) гарантируют атомарность.

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

Поскольку оно будет всегда работать правильно , ноне обязательно так, как вы ожидаете (если вы предполагаете, что процесс A предшествует процессу B).

1 голос
/ 31 августа 2011

Да, конечно, он будет работать правильно.Это не приведет к сбою ОС или процесса.

То, имеет ли это какой-либо смысл, зависит от того, как написано приложение (я) и какова цель файла.

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

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

1 голос
/ 30 августа 2011

Конечно, ядро ​​будет обрабатывать его правильно, для идеи ядра о корректности - что по определению правильно.

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

0 голосов
/ 02 января 2017

write(), writev(), read(), readv() могут генерировать частичные операции записи / чтения, когда объем передаваемых данных меньше запрашиваемого.

Цитирование справочной страницы Linux для writev():

Обратите внимание, что для успешного вызова не является ошибкой передачи меньшего количества байтов, чем запрошено

Цитирование справочной страницы POSIX:

Если write () прерывается сигналом после успешной записи некоторых данных, он возвращает количество записанных байтов.

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

См. сообщение об ошибке в ядре Linux :

Процесс записывает сообщения в файл. [...] записи [...] можно разделить на две части. [...] Таким образом, если сигнал поступает [...], запись прерывается. [...] это совершенно корректное поведение в отношении спецификации (POSIX, SUS, ...)

FIFO и PIPE записывают меньше, чем PIPE_MAX, но гарантированно будут атомарными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...