Атомность fprintf от процессов MPI - PullRequest
0 голосов
/ 26 июня 2019

Вызов fprintf(stderr,...) из процессов MPI никогда не дает для меня чередующихся результатов.

Порядок сообщений от разных процессов MPI, конечно, произвольный. Но никакие два fprintf -с не смешиваются.

Т.е. каждый fprintf ведет себя так, как если бы он был атомарным.

Это поведение гарантировано стандартом? На винде? В Linux (от Posix)?

Имеет ли значение, если FILE буферизован, как stdout?

Ответы [ 2 ]

2 голосов
/ 27 июня 2019

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

Язык C не говорит о том, как отдельные процессы влияют наиспользование друг друга одного и того же устройства.Он ограничен поведением отдельных прогонов отдельных программ.Для POSIX, и я подозреваю, что Windows также в некоторой степени зависит от того, как происходит, что несколько отдельных процессов MPI даже имеют возможность записи на одно и то же устройство одновременно, если это действительно происходит.

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

В POSIX, если совместное использование устройства возникает в результате наследования описания открытого файла от общего предка (shell, master process, и т. Д. .), В дополнение к вышеупомянутым соображениям POSIX устанавливает некоторые требования, подробно изложенные в разделе 2.5.1 .Поскольку ваш пример включает запись в stderr, который по умолчанию небуферизован, ваше использование будет удовлетворять этим требованиям, если вы не изменили его (не) буферизацию.В этом случае POSIX обещает, что

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

И это все, хотя это все же больше, чем в другом случае.«Записано по порядку» не гарантирует, что данные из разных записей будут разделены.На практике, однако, каждый вызов fprintf будет отправлять write() запросов в базовую систему, передавая распечатанные данные в виде одного или нескольких блоков, и, опять же, на практике каждый блок будет записываться непрерывно.

Итак,

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

  • тем не менее неудивительно, что вы видите такую ​​сериализацию на практике.

2 голосов
/ 26 июня 2019

В рамках одного процесса POSIX требует этого - как и C11.Информация POSIX скрыта в маловероятном месте, в спецификации для функции flockfile()funlockfile() и ftrylockfile()):

Все функции, которые ссылаются (FILE *) объекты, за исключением объектов с именами, заканчивающимися на _unlocked, должны вести себя так, как будто они используют flockfile() и funlockfile() для получения права собственности на эти (FILE *) объекты.

Общее описание функций гласит:

Эти функции должны обеспечивать явную блокировку на уровне приложения объектов stdio (FILE *).Эти функции могут использоваться потоком для определения последовательности операторов ввода / вывода, которые выполняются как единое целое.

Таким образом, функции явно манипулируют такими блокировками, как printf() и * 1025.* требуется использовать тоже - по крайней мере, в действительности.

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

*Потоки 1030 * MPI, вероятно, в достаточной степени похожи на потоки POSIX или используют потоки POSIX, поэтому правила также применимы и там.

C11 имеет поддержку потоков и требует поведения - но не функций flockfile() и т. Д. C11 §7.21.2 Потоки ¶8 говорит:

Все функции, которые читают, пишут, позиционируют или запрашивают позицию потока, блокируют поток перед доступом к нему.Они снимают блокировку, связанную с потоком, когда доступ завершен.

...