Некоторое неверное истолкование того, что означает стандартные требования, происходит от использования процессов против потоков, и что это означает для ситуации с «ручкой», о которой вы говорите. В частности, вы пропустили эту часть:
Ручки могут быть созданы или уничтожены явным действием пользователя, не затрагивая описание открытого файла. Некоторые из способов их создания включают fcntl (), dup (), fdopen (), fileno () и
blockquote>fork()
. Они могут быть уничтожены как минимум fclose (), close () и функциями exec. [...] Обратите внимание, что после fork () две ручки существуют там, где они существовали раньше.из раздела спецификации POSIX, приведенного выше. Ссылка на «create [handles using]
fork
» не уточняется далее в этом разделе, но спецификация дляfork()
добавляет немного деталей:У дочернего процесса должна быть своя копия дескрипторов файла родителя. Каждый из описателей файла ребенка должен ссылаться на одно и то же описание открытого файла с соответствующим файловым дескриптором родителя.
blockquote>Соответствующие биты здесь:
- у ребенка есть копии дескрипторов файла родителя
- копии ребенка относятся к той же «вещи», к которой родитель может получить доступ через указанный файл fds
- ors и файл дескриптор ионов - это , а не то же самое; в частности, дескриптор файла является дескриптором в указанном выше смысле.
Это то, что первая цитата относится к тому, когда он говорит: «
fork()
создает [. ..] обрабатывает "- они создаются как копии , и, следовательно, с этой точки отсоединены и больше не обновляются в режиме блокировки.В вашей примерной программе каждый дочерний процесс получает свою собственную копию, которая начинается в том же состоянии, но после акта копирования эти filedescriptors / handle стали независимыми экземплярами , и поэтому они пишут друг с другом. Это вполне приемлемо относительно стандарта, потому что
write()
только guarentees:В обычном файле или другом файле, который можно искать, фактическое письмо данных должно продолжаться из позиции в файле, указанной смещением файла, связанным с файлами. Перед успешным возвратом из write () смещение файла должно быть увеличено на количество фактически записанных байтов.
blockquote>Это означает, что, хотя все они начинают писать с одинаковым смещением (потому что fd копия была инициализирована как таковая), они могут, даже в случае успеха, писать разные суммы (нет стандарта по стандарту, что запрос на запись в
N
байтах будет писать точноN
, это может преуспеть для чего-либо0 <=
actual<= N
), и из-за того, что упорядочение неупорядоченных операций не выполняется, вся приведенная выше примерная программа имеет неуказанные результаты. Даже если записана общая запрашиваемая сумма, все вышеприведенное значение говорит о том, что смещение файла увеличивается - оно не говорит, что оно атомарно (только один раз) увеличивается, и не говорит, что фактическая запись данных будет происходить в атомном режиме.. Одна вещь гарантирована, хотя - вы никогда не увидите ничего в файле, который не был там до какой-либо из записей, или который не попал ни в одну из данных написанной любой из записей. Если вы это сделаете, это будет коррупция и ошибка в реализации файловой системы. То, что вы наблюдали выше, может быть так, что ... если окончательные результаты не могут быть объяснены переупорядочением частей записей.
Использование
O_APPEND
исправляет это, потому что использование что еще раз - см.write()
, делает:Если установлен флаг O_APPEND флагов состояния файла, смещение файла должно быть установлено до конца файл перед каждой записью и никакая промежуточная операция изменения файла не происходит между изменением смещения файла и операцией записи.
blockquote>, который является «до» / «без промежуточного» поведения сериализации, который вы ищете.
Использование потоков частично изменило бы поведение, потому что потоки при создании не получали копии filedescriptors / handle, но работать с фактическим (общим). Нити не будут (обязательно) начинать писать с одного и того же смещения. Но вариант для частичной записи-успеха по-прежнему будет означать, что вы можете видеть чередование, как вы могли бы не видеть. Тем не менее, он может быть полностью совместим со стандартами.
Мораль: не считайте, что стандарт POSIX / UNIX является по умолчанию . Спецификации преднамеренно ослаблены в общем случае и требуют вы, как программист , быть ясными относительно ваших намерений.