Найти в Дзене
Old Programmer

Многозадачность в Linux. Язык C. Статья 14. Проблемы синхронизации

Приветствую вас на канале Old Programmer о программировании и программистах. Тематическое оглавление канала здесь. А тут собраны все ссылки по C/C++. Здесь перечень ссылок на ресурсы, посвященные многозадачности в Linux. Прежде, чем продолжать читать статью, я бы советовал вам еще раз посмотреть предыдущую, где я рассматривал создание двух потоков, которые выводили на консоль буквы 'A' и 'B'. Мы выяснили, что вывод чередуется, поскольку работает то один поток то другой. При чем прерывание вывода может происходить, когда цикл вывода еще не закончился. Но моменты этого прерывания, в общем случае предугадать нельзя. Пример конкурентной работы дочернего и родительского процесса (OS Linux) Сегодня мы рассмотрим похожую задачу но с двумя процессами. О создании потоков можно посмотреть в статьях: И в этом смысле в программе sinh4000.c нет ничего нового. С помощью функции fork() создается дочерний процесс, а затем в родительском процессе и дочернем процессе на консоль опять выводятся буквы.
Оглавление

Приветствую вас на канале Old Programmer о программировании и программистах. Тематическое оглавление канала здесь. А тут собраны все ссылки по C/C++. Здесь перечень ссылок на ресурсы, посвященные многозадачности в Linux.

Прежде, чем продолжать читать статью, я бы советовал вам еще раз посмотреть предыдущую, где я рассматривал создание двух потоков, которые выводили на консоль буквы 'A' и 'B'. Мы выяснили, что вывод чередуется, поскольку работает то один поток то другой. При чем прерывание вывода может происходить, когда цикл вывода еще не закончился. Но моменты этого прерывания, в общем случае предугадать нельзя.

Пример конкурентной работы дочернего и родительского процесса (OS Linux)

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

И в этом смысле в программе sinh4000.c нет ничего нового. С помощью функции fork() создается дочерний процесс, а затем в родительском процессе и дочернем процессе на консоль опять выводятся буквы. При чем каждая букв дважды. Дочерний процесс выводит прописные буквы, а родительский заглавные. Между выводом такой пара делается временная задержка. Если запустить такую программу, то вывод будет перемешиваться, при чем при каждом запуске перемешивание будет разным. Перемешивание происходит и в промежутке между выводом одинаковых букв. Например так

AaaAbBBCbcCDcddDeEefEFfgFGghGHHIhiIiJjJKjkkKlLlLmMMNmnnoNOopOPpqPQqrQRrsRSstSTtuTUuvUVvwVWwxWXxyXYyzYZzZ

А как заставить программу, чтобы прерывание не происходило по-крайней мере между выводами двух одинаковых букв?

Проблема синхронизации процессов (OS Linux)

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

Как может работать такая переменная - флаг? Начальное состояние переменной, назовем ее A положим равной 0. Пусть к ней обращаются два процесса (или потока). Пусть первый процесс проверяет значение переменной, если значение равно 0, то он увеличивает ее на 1 и приступает к выполнению важной для себя (критической) секции кода. Если второй процесс теперь проверит значение переменной и обнаружит, что переменная равна 1, то он переходит в состояние ожидания, проверяя время от времени значение переменной. Как только при очередной проверке значение переменной становится равной 0, то он увеличивает ее на 1 и начинает выполнять свое критическое действие. Почему же переменная стала равной 0? Да потому что первый процесс закончив выполнение своей критической секции, уменьшает значение переменной на 1. Вот в принципе такой незамысловатый механизм использование такой переменной.

Дело в том, однако, что этот механизм несовершенен. Суть вот в чем. Первый процесс может проверить значение переменной A, но не успеет увеличить ее значение, а в этот момент значение проверит второй процесс. И таким образом оба процесс окажутся в критической секции, что может быть недопустимо, по условию задачи. Да, вероятность такая не велика, но не равно нулю. И вот чтобы избежать такой коллизии, используется очень интересный механизм светофоров, который в Linux реализован на уровне ядра. Но об этом в следующей статье.

Замечание. Функция fflush(), которая используется в программе sinh4000.c, сбрасывает в файл (в примере в выходной поток) содержимое буфера. Можете по экспериментировать, проверив, что будет, если убрать эту функцию.

Любите и изучайте многозадачность и не забывайте подписываться на мой канал о программировании и программистах Old Programmer.

Фрагмент программы sinh4000.c
Фрагмент программы sinh4000.c