Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
vovk.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
456 Кб
Скачать
☆

21.Синхронизация потоков по мютексу.

(взято из кертена, изменяй, когда переписываешь)

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

Поток использует объект, называемый мютексом (сокращённо от MUTual Exclusion — взаимное исключение). Этот объект подобен замку в двери: как только поток заблокирует мютекс, никакой другой поток не сможет получить доступ к мютексу до тех пор, пока владеющий мютексом поток его не разблокирует — иными словами, мютекс будет удерживать другие потоки, подобно дверному замку.

Мютекс является «рекомендательной» блокировкой. Если поток не подчиняется правилам использования мютексов, то такая защита бессмысленна. В аналогии с жилым домом эта ситуация подобна тому, как кто-либо вломился бы в ванную комнату через одну из стен, игнорируя соглашение о запретной двери.

Рассмотрим программу с использованием мютексов и условных переменных:

#include<stdio.h>

#include<pthread.h>

int data_ready=0;

pthread_mutex_t mutex=PHTREAD_MUTEX_INITIALIZER;

pthread_cond_t cond=PHTREAD_COND_INITIALIZER;

void * consumer (void * not_used)

{printf(“This is consumer\n”); \\потребитель

while(1)

{ pthread_mutex_lock(&mutex);

while(!data_ready) pthread_cond_wait(&cond, &mutex);

sleep(1); //имитация обработки данных

data_ready=0;

pthread_cond_signal(&cond);

pthread_mutex_signal(&mutex); }}

void * producer(void * not_used)

{printf(“This is producer\n”);\\производитель

while(1)

{ sleep(3); //имитация обработки данных

pthread_mutex_lock(&mutex);

while(data_ready) pthread_cond_wait(&cond, &mutex);

data_ready=1;

pthread_cond_signal(&cond);

pthread_mutex_signal(&mutex);

}}

int main()

{ printf(‘Example\n’);

pthread_create(NULL,NULL,producer,NULL);

pthread_create(NULL,NULL,consumer,NULL);

sleep(30);}

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

Условные переменные надо использовать для точки встречи, а мутексы используются для изменения, а также проверки разделяемых элементов данных.

22.Синхронизация потоков по семафору.

(первые 2 абзаца взяты из кертона, изменяй, когда переписываешь)

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

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

QNX поддерживает два типа семафоров – не именованные и именованные. Разница между ними заключается в том, что к именованному семафору можно обратиться из любого процесса в системе (или даже по сети QNET с другого сетевого хоста), поскольку такой семафор имеет ассоциированное с ним имя в файловой системе QNX. Необходимо помнить, что именованные семафоры, при прочих равных

условиях, медленнее, и требуют для своей работы запущенного в системе менеджера mqueue, который также обслуживает очереди сообщений POSIX.

Для этих двух типов семафоров существует две группы функций, применение которых не должно смешиваться: sem_init() и sem_destroy() - создание и разрушение не именованного семафора,

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

Обе функции возвращают 0 в случае успеха и -1 в случае ошибки. Код ошибки записывается в переменной errno.

sem_open() и sem_close() – открытие и закрытие именованного семафора (в случае отсутствия ранее созданного семафора с таким именем, то его создание). В вопросе подключения и отключения - работа с именованным семафором аналогична работе с обычным файлом. Также для именованных семафоров существует операция sem_unlink(), аналогичная операции unlink() для обычного файла. В функцию

sem_open() передается имя семафора, параметры открытия семафора и дополнительные параметры в случае создания семафора.

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

int sem_wait(sem_t * sem)

int sem_trywait(sem_t * sem)

#include <time.h>

int sem_timedwait(sem_t * sem, const struct timespec * abs_timeout)

Операция разблокирования:

int sem_post(sem_t * sem)

Эта операция увеличивает на единицу (инкремент) внутренний счетчик семафора – в

этом она диаметрально противоположна операции блокирования. Если перед этим

значение счетчика семафора было 0, то одни из потоков, ожидавших

разблокирования семафора переходит в состояние готовности.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]