Читать интересную книгу Основы программирования в Linux - Мэтью Нейл

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 246 247 248 249 250 251 252 253 254 ... 324

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

Важный шаг вперед в сфере параллельного программирования был сделан, когда голландский специалист в области компьютерных наук Эдсгер Дейкстра (Edsger Dijkstra) предложил идею семафоров. Как уже кратко упоминалось в главе 12, семафор — это специальная переменная, которая принимает только целые положительные значения и с помощью которой программы могут действовать только атомарно. В этой главе мы расширим данное ранее упрощенное определение. Будет более подробно рассказано, как действуют семафоры и как для взаимодействия отдельных процессов применяются функции общего назначения вместо особого случая многопоточных программ, которые рассматривались в главе 12.

Определяя более строго, семафор — это специальная переменная, для которой разрешены только две операции, формально именуемые ожиданием или приостановкой (wait) и оповещением (signal). Поскольку в программировании Linux у приостановки и оповещения уже есть специальные значения, мы будем применять оригинальное обозначение:

□ P(переменная-семафор) для приостановки (wait);

□ V(переменная-семафор) для оповещения (signal).

Эти буквы взяты из голландских слов для приостановки (passeren — проходить, пропускать как в случае контрольной точки перед критической секцией) и для оповещения (vrijgeven — предоставлять или освобождать, как в случае отказа от контроля критической секции). Вы можете встретить термины "вверх" (up) и "вниз" (down), применяемые в отношении семафоров по аналогии с использованием сигнальных флажков.

Описание семафора

Простейший семафор — это переменная, способная принимать только значения 0 и 1, бинарный или двоичный семафор. Это наиболее распространенный вид семафора. Семафоры, принимающие много положительных значений, называют семафорами общего вида. В оставшейся части главы мы сосредоточимся на двоичных семафорах.

Определения операций P и V удивительно просты. Предположим, что у вас есть переменная-семафор sv. В этом случае обе операции определяются так, как представлено в табл. 14.1.

Таблица 14.1

Операция Описание Р(sv) Если sv больше нуля, она уменьшается на единицу. Если sv равна 0, выполнение данного процесса приостанавливается V(sv) Если какой-то другой процесс был приостановлен в ожидании семафора sv, переменная заставляет его возобновить выполнение. Если ни один процесс не приостановлен в ожидании семафора sv, значение переменной увеличивается на единицу

Другой способ описания семафора — считать, что переменная sv, равная true, когда доступна критическая секция, уменьшается на единицу с помощью P(sv) и становится равна false, когда критическая секция занята, и увеличивается на единицу операцией V(sv), когда критическая секция снова доступна. Имейте в виду, что обычная переменная, которую вы уменьшаете и увеличиваете на единицу, не годится, т.к. в языках С, С++, C# или практически в любом традиционном языке программирования у вас нет возможности сформировать единую атомарную операцию, проверяющую, равна ли переменная true, и если это так, изменяющую ее значение на false. Именно эта функциональная возможность делает операции с семафором особенными.

Теоретический пример

С помощью простого теоретического примера можно посмотреть, как действует семафор. Предположим, что у вас есть два процесса: proc1 и proc2, оба нуждающиеся в некоторый момент выполнения в монопольном доступе к базе данных. Вы определяете один бинарный семафор sv, который стартует со значением 1 и доступен обоим процессам. Далее обоим процессам нужно выполнить одну и ту же обработку для доступа к критической секции программного кода; эти два процесса могут быть двумя разными выполняющимися экземплярами одной и той же программы.

Оба процесса совместно используют переменную-семафор sv. Как только один процесс выполнил операцию P(sv), он получил семафор и может войти в критическую секцию программы. Второму процессу вход в критическую секцию запрещен, т.к., когда он попытается выполнить операцию P(sv), он вынужден будет ждать до тех пор, пока первый процесс не покинет критическую секцию и не выполнит операцию V(sv), освобождающую семафор.

Требуемый псевдокод у обоих процессов идентичен:

semaphore sv = 1;

loop forever {

 P(sv);

 critical code section;

 V(sv);

 noncritical code section;

}

Код на удивление прост, потому что определение операций P и V наделяет их большими функциональными возможностями.

Рис. 14.1 

На рис. 14.1 показана схема действующих операций P и V, напоминающих ворота в критических секциях программного кода.

Реализация семафоров в Linux

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

Далее приведены объявления функций семафоров:

<b>#include &lt;sys/sem.h&gt;</b>

<b>int semctl(int sem_id, int sem_num, int command, ...);</b>

<b>int semget(key_t key, int num_sems, int sem_flags);</b>

<b>int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);</b>

1 ... 246 247 248 249 250 251 252 253 254 ... 324
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Основы программирования в Linux - Мэтью Нейл.

Оставить комментарий