Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Синхронизация с помощью семафоров






Для семафоров есть два набора интерфейсных функций: один взят из POSIX Realtime Extensions (дополнения POSIX для режима реального времени) и применяется для потоков, а другой, известный как семафоры System V, обычно применяется для синхронизации процессов. Оба набора не гарантируют взаимозаменяемости и хотя очень похожи, используют вызовы разных функций.

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

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

Имена функций семафоров начинаются не с префикса

pthread_

, как большинство функций, относящихся к потокам, а с

sem_

Для работы с потоками применяют четыре базовые функций семафоров. Они все очень просты.

Семафор создается с помощью функции

sem_init

, которая объявляется следующим образом.

#include < semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

Эта функция инициализирует объект-семафор, на который указывает параметр

sem

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

pshared

управляет типом семафора. Если

pshared

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

pshared

приводила к аварийному завершению вызова.

Следующая пара функций управляет значением семафора и объявляется следующим образом.

#include < semaphore.h>

int sem_wait(sem_t* sem);

int sem_post(sem_t* sem);

Обе они принимают указатель на объект-семафор, инициализированный вызовом

sem_init

Функция

sem_post

атомарно увеличивает значение семафора на 1. Атомарно в данном случае означает, что если два потока одновременно пытаются увеличить значение единственного семафора на 1, они не мешают друг другу, как в случае двух программ, которые читают, увеличивают и записывают значение в файл в одно и то же время. Если обе программы пытаются увеличить значение на 1, семафор всегда будет корректно увеличивать значение на 2.

Функция

sem_wait

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

sem_wait

для семафора со значением 2, поток продолжит выполнение, а семафор будет уменьшен до 1. Если

sem_wait

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

sem_wait

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






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.