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

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

Следующая программа на языке C должна проиллюстрировать состояние гонки между дочерними и родительскими процессами:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
     fork();
     printf("\n 1234567890 \n");
     return 0;
}

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

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

Но когда я пробую ту же программу на своемАрч Линукс, он никогда не выдает такого результата. Всегда один за другим.

 1234567890 

 1234567890 

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

решение1

Вызов 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
...

решение2

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

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

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

Связанный контент