Состояние гонки не работает в Arch Linux

Предполагается, что следующая программа на C проиллюстрирует состояние ребенка b / w для условий гонки и родительских процессов:

#include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { fork(); printf("\n 1234567890 \n"); return 0; } 

Когда мои друзья выполняют его (на Ubuntu ), они получают ожидаемый результат, который смешался 1234567890s

Один пример: 12312345645678907890

Но когда я пытаюсь использовать ту же программу на моем Arch Linux , она никогда не дает такого вывода. Его всегда один за другим.

  1234567890 1234567890 

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

В вызове printf будет выполняться один или несколько системных вызовов write(2) , и порядок, который они обрабатывают, будет фактическим порядком вывода. Один или несколько, потому что это зависит от буферизации внутри библиотеки C. С выходом с линейным буфером (переход к терминалу) вы, вероятно, получите два вызова для write , один раз для начальной строки новой строки, а другой для остальных.

 write(1, "\n", 1); write(1, " 1234567890 \n", 13); 

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

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

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

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

Что-то вроде этого:

 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; setbuf(stdout, NULL); /* explicitly unbuffered */ int x = fork(); for (i = 0 ; i < 500 ; i++) { printf("%d", !!x); } if (x) { wait(NULL); printf("\n"); } return 0; } 

Дает мне вывод, как показано ниже. Большую часть времени это не всегда. Система должна решить, как планировать процессы. Непредсказуемость – вот почему мы обычно стараемся избегать условий гонки.

 111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111 111100000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000010000001001100 110000000011001100110011000000010011001100110000000100110011001100000001001 100110011000000010011001100110000000100110011001100000001001100110011000000 ... 

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

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

«Фиксация», скорее всего, потребует перезаписи системного вызова fork() или компонентов в ядре, участвующих в нем.