
- •«Объединения» - завершение потоков
- •«Барьеры»
- •Механизм семафоров
- ••При создании семафора S с ним связывается очередь заблокированных процессов; очередь обслуживается в
- •Обеспечение взаимного исключения
- •Общий (счетный) семафор
- •Пример: «Поставщик-Потребитель»
- •«Поставщик-Потребитель» - реализация
- •«Поставщик-Потребитель» - комментарии
- •Недостатки механизма семафоров
- •Семафоры (POSIX)
- •Мьютекс (mutual exclusion)
- •Попытка вызова unlock() «не владельцем»
- •Мьютекс - инициализация и захват
- •Освобождение
- •Мьютекс QNX (POSIX)
- •Мьютекс и инверсия приоритетов
- •Условные переменные
- •Механизм сообщений (QNX)
- •smsg
- •Пример - Клиент
- •Пример - Сервер

Семафоры (POSIX)
Неименованные семафоры
#include <semaphore.h> (sem_t mySem;)
int sem_init( sem_t* sem, int pshared, unsigned value );
*sem – указатель на объект, который мы хотим инициировать pshared – не «0», если мы хотим, чтобы sem разделялся процессами через
разделяемую память
value – значение семафора (> 0, если «0», то семафор блокирован)
int sem_destroy( sem_t * sem ); int sem_wait( sem_t * sem );
int sem_post( sem_t * sem ) – инкремент значения семафора;
int sem_trywait( sem_t * sem ) - неблокирующий декремент значения семафора, возвращает значение счетчика
Именованные семафоры – межпроцессная и сетевая поддержка; примитивы другие.
12. Механизмы синхронизации |
2015 v.01 |
11 |

Мьютекс (mutual exclusion)
Class Семафор {
Очередь: УказательНаОчередьЗаблокированных НачЗначение: 0..N; (*)
ТекЗначение: 0..M; (*) P(); V();
}
(*) Для двоичного семафора - 0..1
mutex {
Очередь: УказательНаОчередьЗаблокированных boolean: занят, свободен;
Задача: владелец;
lock(); unlock(); //неделимые операции
}
12. Механизмы синхронизации |
2015 v.01 |
12 |

Попытка вызова unlock() «не владельцем»
Приложение
Создать_Mutex(S);
Задача 1 |
|
Задача 2 |
|
Задача 3 |
S.lock(); |
|
S.lock(); |
|
S.unlock(); |
КС1 |
|
КС2 |
|
|
|
|
|
||
S.unlock(); |
|
S.unlock(); |
|
|
|
|
|
|
|
Задача 1 - владелец |
Бросается |
t |
|
||
|
Исключение |
t |
|
|
|
Задача 2 – становиться владельцем |
|
|
Задача 3 – Ошибка! |
|
t |
|
|
12. Механизмы синхронизации |
13 |

Мьютекс - инициализация и захват |
TCB-владелец |
|||
Создать_mutex(mutex S): |
|
|
|
|
|
|
|
||
1. |
S = new mutex(); |
|
|
|
2. |
S.Очередь = СоздатьОчередь(); |
|
Приоритет |
|
3. |
S.Владелец = nill; |
|
|
|
|
ТПриоритет |
|
||
4. |
S.Состояние = свободен; |
|
|
|
lock(): |
|
|
|
|
|
TCB- ТекПроц |
|||
1. |
Запретить_Прерывания; |
|
||
|
|
|
2.if(Состояние==занят) then
2.1.Владелец.ТПриоритет = ТекПроц.Приоритет;
2.2.ждать(Состояние==свободен);
3.Владелец = ТекПроц;
4.Состояние = занят;
5.Разрешить_Прерывания;
действие 2.1. – приоритет ТекПроц будет выше приоритета Владелец; иначе ТекПроц не мог бы вытеснить владельца и вызвать loc()
12. Механизмы синхронизации |
2015 v.01 |
14 |

Освобождение
unlock();
1.Запретить_Прерывания;
2.if(Владелец==ТекПроц) then
2.1.R = Взять_Из_Очереди(Очередь);
2.2.Поставить_В_Очередь(R,ОчердьГотовых)
2.3.Состояние = свободен;
else Исключение; // Еще одна особенность
3.Владелец.ТПриоритет = Владелец.Приоритет;
4.Владелец = nill;
5.Разрешить_Прерывания();
12. Механизмы синхронизации |
2015 v.01 |
15 |

|
Мьютекс QNX (POSIX) |
struct pthread_mutex_attr_t { |
|
int protocol; |
pthread_mutex_init(…) |
int prioceiling; |
pthread_mutex_lock(…) |
unsigned owner; |
pthread_mutex_unlock(…) |
. . . |
|
}
pthread_mutexattr_setprotocol(.., int protocol) protocol - PTHREAD_PRIO_INHERIT, PTHREAD_PRIO_PROTECT int pthread_mutexattr_getprotocol(…)
pthread_mutexattr_setprioceiling(.., int prioceiling)
int pthread_mutexattr_getprioceiling(.., int prioceiling) рrioceiling – приоритет, присваиваемый потоку,
захватившему мьютекс (см. слайд 7, struct sched_param)
12. Механизмы синхронизации |
2015 v.01 |
16 |

Мьютекс QNX (POSIX)
#include <pthread.h> (pthread_mutex_t mutex;)
int sem_init(pthread_mutex_t* mutex, pthread_mutex_attr* attr);
*mutex – указатель на объект, который мы хотим инициировать *attr – ссылка на структуру атрибутов
int pthread_mutex_destroy(pthread_mutex_t* mutex); int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex); -
пытается захватить мьютекс, а если он уже занят, то выполнение продолжается без блокировки потока
int pthread_mutex_unlock(pthread_mutex_t *mutex);
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec* abs_timeout);
блокировка прекращается по истечению времени
12. Механизмы синхронизации |
2015 v.01 |
17 |

Мьютекс и инверсия приоритетов
struct |
_sync_attr_t { |
#include <sched.h> |
int |
protocol; |
|
int |
flags; |
struct sched_param { |
int |
prioceiling; |
int32_t sched_priority; |
int |
clockid; |
int32_t sched_curpriority; |
int |
reserved[4]; |
. . . |
} |
|
} |
pthread_mutexattr_setprotocol(pthread_mutexattr_t* attr, int protocol)
int pthread_mutexattr_getprotocol(…)
protocol:
PTHREAD_PRIO_INHERIT,(по умолчанию)
PTHREAD_PRIO_PROTECT pthread_mutexattr_setprioceiling(.., int prioceiling)
int pthread_mutexattr_getprioceiling(.., int prioceiling)
рrioceiling – приоритет, присваиваемый потоку, захватившему мьютекс
12. Механизмы синхронизации 2015 v.01 |
18 |

Условные переменные
#include <pthread.h>
int pthread_cond_init( pthread_cond_t* cond, pthread_condattr_t* attr );
int pthread_cond_destroy( pthread_cond_t* cond); int pthread_cond_broadcast( pthread_cond_t* cond);
|
• |
Поток А захватывает |
||
Поток А |
• |
мьютекс |
|
|
Поток А блокируется на УП |
||||
pthread_mutex_lock(&m); |
||||
|
и освобождает мьютекс |
|||
. . . |
• |
|||
while (!arbitrary_condition){ |
Поток В «посылает сигнал» |
|||
pthread_cond_wait(&cv, &m); |
|
и освобождает мьютекс |
||
} |
• |
Поток А разблокируется, |
||
. . . |
||||
|
захватывает мьютекс и |
|||
pthread_mutex_unlock(&m); |
|
|||
|
|
ставится в очередь |
|
|
Поток В |
• |
«готовых» |
|
|
Поток А продолжает |
|
|||
pthread_cond_signal(&cv); |
|
|||
|
выполнение и освобождает |
|||
|
|
|||
12. Механизмы синхронизации |
2015 v.01 |
мьютекс |
19 |
|
|

Механизм сообщений (QNX)
Клиент Сервер
2 MsgReceive
Блокировка
1 MsgSend
Блокировка
3 MsgReply
Клиент
. . .
int coid;
coid = ConnectAttach(0, getpid(), chid, 0, 0); /* Готовим сообщение */
MsgSend(coid, smsg, sizeof(smsg),
rmsg, sizeof(rmsg));
/* Обрабатываем ответ */
. . .
Сервер
int chid;
chid = ChannelCreate(0);
. . .
for (;;){
rcvid = MsgReceive(chid, &rmsg, sizeof(msg), NULL);
/* Обрабатываем сообщение */ MsgReply(rcvid, EOK, &smsg, sizeof(msg));
. . .
}
12. Механизмы синхронизации |
2015 v.01 |
20 |