Могут ли два процесса в ос unix одновременно держать открытым один и тот же файл

Обновлено: 05.07.2024

Я знаю, что это немного теоретический вопрос, но пока не получил удовлетворительного ответа. Вот и подумал поставить этот вопрос здесь. У меня есть несколько процессов C ++ (также хотел бы знать поведение потока), которые утверждают, чтобы заменить один и тот же файл одновременно. Насколько это безопасно делать в Linux (используя Ubuntu 14.04 и Centos 7)? Нужно ли ставить замки?

2 ответа

Файловые системы ОС на основе Unix, таких как Linux, разработаны с учетом inode, которые являются внутренними записи, описывающие различные метаданные о файле. Обычно они не взаимодействуют напрямую с пользователями или программами, но их наличие дает этим файловым системам уровень косвенности, который позволяет им предоставлять некоторую полезную семантику, которую не могут другие ОС (читай: Windows).

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

Результатом этого является то, что в Linux вполне допустимо удалить (или переименовать) файл в любое время, даже если другие потоки / процессы находятся в процессе его использования; Ваше удаление будет успешным, и любые другие программы, у которых этот файл открыт в этот момент, могут просто продолжить чтение / запись / использование его, точно так, как если бы он не был удален. Единственное отличие состоит в том, что имя файла больше не будет отображаться в его каталоге, и когда они вызывают fclose() (или close() или т. Д.) В файле, данные файла исчезают.

Поскольку выполнение mv new.txt old.txt по существу аналогично выполнению rm old.txt ; mv new.txt old.txt , не должно быть проблем с выполнением этого из нескольких потоков без какой-либо синхронизации. (обратите внимание, что немного другая ситуация, когда несколько потоков или процессов открывают один и тот же файл одновременно и записывают в него одновременно, немного опаснее; ничего не произойдет, но им будет легко перезаписать данные друг друга и испортить файл, если они не осторожны)

Это во многом зависит от того, что именно вы собираетесь делать и как вы используете файлы. В общем, в системах Unix / Posix, таких как Linux, все файловые вызовы будут успешными, если их создаст несколько процессов, и в общем случае ОС обрабатывает конфликты «последний побеждает». По сути, все модификации файловой системы сериализуются, поэтому файловая система всегда находится в согласованном состоянии. Но в остальном это бесплатно для всех.

Здесь много подробностей. При открытии файла, такого как O_EXCL , используются флаги, которые могут привести к сбою, если другой процесс сделал это первым (своего рода блокировка). Есть рекомендации (иначе операционная система никого не заставляет обращать на них внимание), блокирующие системы, такие как flock (попробуйте ввести man 2 flock , чтобы узнать больше) для содержимого файла. Есть более специфичная для Linux система обязательной блокировки.

И есть также такие детали, как «Что произойдет, если кто-то удалил файл, который я открыл?» что другой ответ объясняет правильно и хорошо.

И, наконец, существует целый ряд деталей, связанных с тем, гарантировано ли, что какое-то конкретное изменение в файловой системе будет записано на всю вечность, или есть ли вероятность его исчезновения, если кто-то щелкнет выключателем питания. И это полторы беспорядка, как только вы действительно погрузитесь в это, между хитрым аппаратным обеспечением, которое лжет ОС, о вещах к запутанной болтовне разных системных вызовов Linux, охватывающих различные аспекты этой проблемы, часто входя в Linux из разных эпох История Unix / Posix и взаимодействие друг с другом странным и загадочным образом.

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

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

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

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

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

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

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

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

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

Более тонкий подход заключается в прозрачной для пользователя блокировке отдельных структур ядра, отвечающих за работу с файлами части пользовательских данных. Например, в ОС Unix во время системного вызова, осуществляющего ту или иную операцию с файлом, как правило, происходит блокирование индексного узла, содержащего адреса блоков данных файла. Может показаться, что организация блокировок или запрета более чем одному процессу работать с файлом во время выполнения системного вызова является излишней, так как в подавляющем большинстве случаев выполнение системных вызовов и так не прерывается, то есть ядро работает в условиях невытесняющей многозадачности. Однако в данном случае это не совсем так. Операции чтения и записи занимают продолжительное время и лишь инициируются центральным процессором, а осуществляются по независимым каналам, поэтому установка блокировок на время системного вызова является необходимой гарантией атомарности операций чтения и записи. На практике оказывается достаточным заблокировать один из буферов кэша диска, в заголовке которого ведется список процессов, ожидающих освобождения данного буфера. Таким образом, в соответствии с семантикой Unix изменения, сделанные одним пользователем, немедленно становятся "видны" другому пользователю, который держит данный файл открытым одновременно с первым.

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

Обычные файлы

Обычные (или регулярные) файлы реально представляют собой набор блоков (возможно, пустой) на устройстве внешней памяти, на котором поддерживается файловая система. Такие файлы могут содержать как текстовую информацию (обычно в формате ASCII), так и произвольную двоичную информацию. Файловая система не предписывает обычным файлам какую-либо структуру, обеспечивая на уровне пользователей представление обычного файла как последовательности байтов. Используя базовые системные вызовы (или функции библиотеки ввода/вывода, которые мы рассмотрим в разделе 4), пользователи могут как угодно структуризовать файлы. В частности, многие СУБД хранят базы данных в обычных файлах ОС UNIX.

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

Файлы-каталоги

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

Структура файла-каталога очень проста. Фактически, каталог - это таблица, каждый элемент которой состоит из двух полей: номера i-узла данного файла в его файловой системе и имени файла, которое связано с этим номером (конечно, этот файл может быть и каталогом). Если просмотреть содержимое текущего рабочего каталога с помощью команды ls -ai, то можно получить, например, следующий вывод:

Этот вывод демонстрирует, что в любом каталоге содержатся два стандартных имени - "." и "..". Имени "." сопоставляется i-узел, соответствующий самому этому каталогу, а имени ".." - i-узел, соответствующий "родительскому" каталогу данного каталога. "Родительским" (parent) каталогом называется каталог, в котором содержится имя данного каталога. Файлы с именами "first_file" и "second_file" - это разные файлы с номерами i-узлов 54 и 65 соответственно. Файл "second_again" представляет пример так называемой жесткой ссылки: он имеет другое имя, но реально описывается тем же i-узлом, что и файл "second_file". Наконец, последний элемент каталога описывает некоторый другой каталог с именем "dir2".

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

mkdir, производящего новый каталог,

rmdir, удаляющий пустой (незаполненный) каталог,

getdents, позволяющего прочитать содержимое указанного каталога.

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

Специальные файлы

Специальные файлы не хранят данные. Они обеспечивают механизм отображения физических внешних устройств в имена файлов файловой системы. Каждому устройству, поддерживаемому системой, соответствует, по меньшей мере, один специальный файл. Специальные файлы создаются при выполнении системного вызова mknod, каждому специальному файлу соответствует порция программного обеспечения, называемая драйвером соответствующего устройства. При выполнении чтения или записи по отношению к специальному файлу, производится прямой вызов соответствующего драйвера, программный код которого отвечает за передачу данных между процессом пользователя и соответствующим физическим устройством.

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

cp myfile /tmp/kuz

перепишет файл с именем myfile в подкаталог kuz рабочего каталога. В то же время, команда

cp myfile /dev/console

выдаст содержимое файла myfile на системную консоль вашей установки.

Различаются два типа специальных файлов - блочные и символьные (подробности см. в разделе 3.3). Блочные специальные файлы ассоциируются с такими внешними устройствами, обмен с которыми производится блоками байтов данных, размером 512, 1024, 4096 или 8192 байтов. Типичным примером подобных устройств являются магнитные диски. Файловые системы всегда находятся на блочных устройствах, так что в команде mount обязательно указывается некоторое блочное устройство.

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

При обмене данными с блочным устройством система буферизует данные во внутреннем системном кеше. Через определенные интервалы времени система "выталкивает" буфера, при которых содержится метка "измененный". Кроме того, существуют системные вызовы sync и fsync, которые могут использоваться в пользовательских программах, и выполнение которых приводит к выталкиванию измененных буферов из общесистемного пула. Основная проблема состоит в том, что при аварийной остановке компьютера (например, при внезапном выключении электрического питания) содержимое системного кеша может быть утрачено. Тогда внешние блочные файлы могут оказаться в рассогласованном состоянии. Например, может быть не вытолкнут супер-блок файловой системы, хотя файловая система соответствует его вытолкнутому состоянию. Заметим, что в любом случае согласованное состояние файловой системы может быть восстановлено (конечно, не всегда без потерь пользовательской информации).

Обмены с символьными специальными файлами производятся напрямую, без использования системной буферизации.

Связывание файлов с разными именами

Файловая система ОС UNIX обеспечивает возможность связывания одного и того же файла с разными именами. Часто имеет смысл хранить под разными именами одну и ту же команду (выполняемый файл) командного интерпретатора. Например, выполняемый файл традиционного текстового редактора ОС UNIX vi обычно может вызываться под именами ex, edit, vi, view и vedit.

Можно узнать имена всех связей данного файла с помощью команды ncheck, если указать в числе ее параметров номер i-узла интересующего файла. Например, чтобы узнать все имена, под которыми возможен вызов редактора vi, можно выполнить следующую последовательность команд (третий аргумент команды ncheck представляет собой имя специального файла, ассоциированного с файловой системой /usr):

$ ncheck -i 372 /dev/dsk/sc0d0s5

Ранее в большинстве версий ОС UNIX поддерживались только так называемые "жесткие" связи, означающие, что в соответствующем каталоге имени связи сопоставлялось имя i-узла соответствующего файла. Новые жесткие связи могут создаваться с помощью системного вызова link. При выполнении этого системного вызова создается новый элемент каталога с тем же номером i-узла, что и ранее существовавший файл.

Начиная с "быстрой файловой системы" университета Беркли, в мире UNIX появились "символические связи". Символическая связь создается с помощью системного вызова symblink. При выполнении этого системного вызова в соответствующем каталоге создается элемент, в котором имени связи сопоставляется некоторое имя файла (этот файл даже не обязан существовать к моменту создания символической связи). Для символической связи создается отдельный i-узел и даже заводится отдельный блок данных для хранения потенциально длинного имени файла.

Для работы с символьными связями поддерживаются три специальных системных вызова:

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

lstat - аналогичен системному вызову stat (получить информацию о файле), но относится к символической ссылке;

lchowm - аналогичен системному вызову chown, но используется для смены пользователя и группы самой символической ссылки.

Именованные программные каналы

Программный канал (pipe) - это одно из наиболее традиционных средств межпроцессных взаимодействий в ОС UNIX. В русской терминологии использовались различные переводы слова pipe (начиная от "трубки" и заканчивая замечательным русским словом "пайп"). Мы считаем, что термин "программный канал" наиболее точно отражает смысл термина "pipe".

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

Однако различаются два подвида программных каналов - неименованные и именованные. Неименованные программные каналы появились на самой заре ОС UNIX (см. раздел 1.2). Неименованный программный канал создается процессом-предком, наследуется процессами-потомками, и обеспечивает тем самым возможность связи в иерархии порожденных процессов. Интерфейс неименованного программного канала совпадает с интерфейсом файла (более подробно см. п. 3.4.4). Однако, поскольку такие каналы не имеют имени, им не соответствует какой-либо элемент каталога в файловой системе.

Именованному программному каналу обязательно соответствует элемент некоторого каталога и даже собственный i-узел. Другими словами, именованный программный канал выглядит как обычный файл, но не содержащий никаких данных до тех пор, пока некоторый процесс не выполнит в него запись. После того, как некоторый другой процесс прочитает записанные в канал байты, этот файл снова становится пустым. В отличие от неименованных программных каналов, именованные программные каналы могут использоваться для связи любых процессов (т.е. не обязательно процессов, входящих в одну иерархию родства). Интерфейс именованного программного канала практически полностью совпадает с интерфейсом обычного файла (включая системные вызовы open и close), хотя, конечно, необходимо учитывать, что поведение канала отличается от поведения файла (подробности см. в п. 3.4.4).

Файлы, отображаемые в виртуальную память

В современных версиях ОС UNIX (например, в UNIX System V.4) появилась возможность отображать обычные файлы в виртуальную память процесса с последующей работой с содержимым файла не с помощью системных вызовов read, write и lseek, а с помощью обычных операций чтения из памяти и записи в память. Заметим, что этот прием был базовым в историческом предшественнике ОС UNIX - операционной системе Multics (см. раздел 1.1).

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

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

Синхронизация при параллельном доступе к файлам

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

В System V.4 появились средства, позволяющие процессам синхронизировать параллельный доступ к файлам. В принципе, было бы логично связать синхронизацию доступа к файлу как к единому целому с системным вызовом open (т.е., например, открытие файла в режиме записи или обновления могло бы означать его монопольную блокировку соответствующим процессом, а открытие в режиме чтения - совместную блокировку). Так поступают во многих операционных системах (начиная с ОС Multics). Однако, по отношению к ОС UNIX такое решение принимать было слишком поздно, поскольку многочисленные созданные за время существования системы прикладные программы опирались на свойство отсутствия автоматической синхронизации.

Поэтому разработчикам пришлось пойти "обходным путем". Ядро ОС UNIX поддерживает дополнительный системный вызов fcntl, обеспечивающий такие вспомогательные функции, относящиеся к файловой системе, как получение информации о текущем режиме открытия файла, изменение текущего режима открытия и т.д. В System V.4 именно на системный вызов fcntl нагружены функции синхронизации.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

цитата:

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

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

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

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

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

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

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

Читайте также: