Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
5 семестр / Литература / лекция4.процессы и потоки.pptx
Скачиваний:
13
Добавлен:
18.02.2023
Размер:
695.59 Кб
Скачать

УСЛОВНЫЕ ПЕРЕМЕННЫЕ В ПАКЕТЕ PTHREADS

Наиболее важные вызовы, связанные с условными переменными:

Заблокированный поток зачастую ожидает, пока сигнализирующий поток не совершит определенную работу, не освободит какие-то ресурсы или не выполнит какие-нибудь другие действия. Только после этого заблокированный поток продолжает свою работу.

/* Количество производимого */
/* используется для сигнализации */ /* буфер, используемый между производителем и потребителем */ /* производство данных */

УСЛОВНЫЕ ПЕРЕМЕННЫЕ И МЬЮТЕКСЫ

#include <stdio.h> #include <pthread.h> #define MAX 1000000000 pthread_mutex_t the_mutex;

pthread_cond_t condc, condp; int buffer = 0;

void *producer(void *ptr)

{int i;

 

for (i= 1; i <= MAX; i++) {

 

 

pthread_mutex_lock(&the mutex);

/* получение исключительного

 

 

доступа к буферу */

 

while (buffer != 0) pthread_cond_wait(&condp, &the_mutex);

 

buffer = i;

/* помещение записи в буфер */

 

pthread_cond_signal(&condc);

/* активизация потребителя */

 

pthread_mutex_unlock(&the mutex);

/* освобождение доступа к буферу */

 

}

 

 

pthread exit(0);

 

}

 

 

void

*consumer(void *ptr)

/* потребление данных */

{

int i;

 

 

for (i = 1; i <= MAX; i++) {

 

 

pthread_mutex_lock(&the_mutex);

/* получение исключительного

 

доступа к буферу */

 

while (buffer ==0 ) pthread_cond_wait(&condc, &the_mutex);

 

buffer = 0;

/* извлечение записи из буфера */

 

pthread_cond_signal(&condp);

/* активизация производителя */

 

pthread_mutex_unlock(&the_mutex);

/* освобождение доступа к буферу */

 

}

 

 

pthread exit(0);

 

}

 

 

УСЛОВНЫЕ ПЕРЕМЕННЫЕ И МЬЮТЕКСЫ

int main(int argc, char **argv)

{

pthread_t pro, con; pthread_mutex_init(&the mutex, 0); pthread_cond_init(&condc, 0); pthread_cond_init(&condp, 0); pthread_create(&con, 0, consumer, 0); pthread_create(&pro, 0, producer, 0); pthread_join(pro, 0); pthread_join(con, 0); pthread_cond_destroy(&condc); pthread_cond_destroy(&condp); pthread_mutex_destroy(&the mutex);

}

МЬЮТЕКСЫ

Общая последовательность для защиты общих данных с помощью мьютекса:

блокируем мьютекс

работаем с общими данными

разблокируем мьютекс

МОНИТОРЫ

Взаимная блокировка

МОНИТОРЫ

Чтобы облегчить написание безошибочных программ, Бринч Хансен (Brinch Hansen) в 1973 году и Хоар (Hoare) в 1974 году предложили высокоуровневый синхронизационный примитив, названный монитором.

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

Для использования мониторов нужен язык, в который они встроены.

МОНИТОРЫ

У мониторов имеется весьма важное свойство, позволяющее успешно справляться со взаимными исключениями: в любой момент времени в мониторе может быть активен только один процесс.

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

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

МОНИТОРЫ

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

В случае с решением задачи производителя-потребителя проще всего поместить все тесты на заполненность и опустошенность буфера в процедуры монитора, но как тогда производитель должен заблокироваться, обнаружив, что буфер заполнен до отказа?

Для решения этой проблемы нужно ввести условные переменные, а также две проводимые над ними операции — wait и signal.

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

МОНИТОРЫ

Этот другой процесс, например потребитель, может активизировать работу своего приостановленного партнера, осуществив операцию signal в отношении условной переменной, изменения значения которой ожидает его партнер.

Чтобы в мониторе в одно и то же время не находились сразу два активных процесса, нам необходимо правило, предписывающее дальнейшее развитие событий после осуществления операции signal.

Хоар предложил позволить только что активизированному процессу приостановить работу другого процесса. Бринч Хансен предложил разрешить проблему, потребовав обязательного и немедленного выхода из монитора того процесса, который осуществил операцию signal. Иными словами, операция signal должна фигурировать только в качестве завершающей операции в процедуре монитора.

ПЕРЕДАЧА

СООБЩЕНИЙ

Этот метод взаимодействия процессов использует два примитива, send и receive, которые, подобно семафорам и в отличие от мониторов, являются системными вызовами, а не конструкциями языка.

Как таковые они легко могут быть помещены в библиотечные процедуры, например:

send(destination, &message);

или

receive(source, &message);

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