Вы правы, что беспокоитесь об атомарности здесь.
Если другой процесс или другой поток в том же процессе также пишет в тот же канал связи, то
write(fd, "ABCD", 4);
будет записывать четыре байта «ABCD» атомарно, в том смысле, что выходные данные других авторов не могут появляться в середине этих четырех байтов. С другой стороны,
write(fd, "A", 1);
write(fd, "B", 1);
write(fd, "C", 1);
write(fd, "D", 1);
будет записывать каждый байт отдельно, а вывод других писателей может появляться между буквами.
Однако атомарность толькогарантировано для short записи, где третий аргумент меньше, чем константа PIPE_BUF
. Если вы пишете больше данных, чем это, вы не сможете гарантировать, что выходные данные других авторов не появятся посередине. PIPE_BUF
может быть столь же маленьким, как 512, но обычно несколько больше, чем в наши дни.
Самым простым способом убедиться в этом для себя является использование fork
и запись в стандартный вывод:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
} else if (pid == 0) {
// child
write(1, "ABCD", 4); sleep(1);
write(1, "A", 1); sleep(1);
write(1, "B", 1); sleep(1);
write(1, "C", 1); sleep(1);
write(1, "D", 1);
return 0;
} else {
// parent
write(1, "1234", 4); sleep(1);
write(1, "1", 1); sleep(1);
write(1, "2", 1); sleep(1);
write(1, "3", 1); sleep(1);
write(1, "4", 1);
waitpid(pid, 0, 0);
write(1, "\n", 1);
return 0;
}
}
Эта программа напечатает что-то вроде 1234ABCD1AB23CD4
. Первый ABCD
всегда будет отображаться как группа, а первый 1234
всегда будет отображаться как группа, но любой из них может быть первым;вторые ABCD
и 1234
могут быть произвольно перепутаны.
(Вопрос теста: почему я поставил окончательный write(1, "\n", 1)
в родительском, после * waitpid
?)