- •Алгоритмы
- •План
- •Литература
- •Необходимость
- •Пример: файл данных
- •Критические участки
- •Взаимоисключающий
- •Атомарные операции
- •Пример: вставка в
- •Синхронизация в системах с общей памятью
- •Атомарные операции с общей памятью
- •Блокировки
- •Захват и освобождение блокировок
- •Обеспечение атомарности с помощью блокировки
- •Предотвращение состояний конкуренции
- •Взаимоблокировка
- •Самоблокировка
- •Предотвращение
- •Еще раз о состоянии конкуренции
- •Спин-блокировки
- •Спин блокировка с атомарными операциями
- •Блокировки без атомарных операций
- •Свойства
- •Доказательство
- •Доказательство отсутствия бесконечного ожидания
- •Алгоритмы для N процессоров
- •Блокировка в состоянии конфликта
- •Эффективность блокировок
- •Спин-блокировки для реальных систем
- •Блокировки чтения-записи
- •Пример использования блокировки чтения-записи
- •Пример реализации rw блокировки
- •Отказ обслуживания записи при обслуживании чтения
- •Блокировки чтения-записи с приоритетом на запись
- •Использование секвентных блокировок
- •Реализация seqlock
- •Недостатки spinlock
- •Семафоры
- •Операции с семафорами
- •Mutex
- •Пример:
- •Счетный семафор
- •Реализация семафоров
- •Пример реализации семафора
- •Семафоры чтения записи
- •Особенности семафоров
- •Условные переменные
- •Пример использование
- •Мониторы
- •Барьер
- •Блокировки в системах с распределенной памятью
- •Пример реализации барьера
- •Вопросы?
Блокировки чтения-записи
Несколько операций чтения могут выполняться параллельно с одной и той же переменной
Операции записи должны быть строго последовательными
При записи чтение должно запрещаться
Такую возможность обеспечивает блокировка чтения-записи
Пример использования блокировки чтения-записи
//Общая переменная |
//Общая переменная |
||
rw_lock |
lock; |
rw_lock |
lock; |
//общий |
связанный список |
//общий |
связанный список |
Llist list; |
Llist list; |
||
Поток 1 |
Поток 2 |
write_lock(&lock); |
read_lock(&lock); |
//эксклюзивный |
//параллельный |
//доступ на запись |
//доступ на чтение |
insert(list); |
read(list); |
write_unlock(&lock); |
read_unlock(&lock); |
Пример реализации rw блокировки
int readers=0; |
void write_lock(){ |
int writes=0; |
while(1){ |
Spinlock l; |
lock(l); |
|
if(!writers && !readers) { |
void read_lock(){ |
writers++; |
while(1){ |
unlock(); |
lock(l); |
break; |
if(!writers) { |
} |
readers++; |
unlock(l); |
unlock(); |
} |
break; |
} |
} |
|
unlock(l); |
Void write_unlock(){ |
} |
lock(l); |
} |
writers--; |
|
unlock(l) |
Void read_unlock(){ |
} |
lock(l); |
|
readers--; |
|
unlock(l) |
|
} |
|
Отказ обслуживания записи при обслуживании чтения
Пример:
1 поток записи
1000 потоков чтения
Один поток чтения захватывает блокировку
Все потоки чтения ею пользуются
1 поток записи ждет долго!
Реальный пример
Системный таймер
1 поток записывает значение времени в общую переменную
Остальные потоки читают это значение
В нашем случае часы будут отставать
Блокировки чтения-записи с приоритетом на запись
Секвентная блокировка (seq_lock)
Вводится счетчик
Перед началом каждой операции записи значение счетчика увеличивается на 1
После окончания записи значение счетчика снова увеличивается на 1
Вначале и в конце чтения значение счетчика проверяется
Если они четные, то новый акт записи закончен
Если значения одинаковы, то акт записи в процессе чтения не начинался
Использование секвентных блокировок
//Общая переменная time_t time; //Блокировка Seqlock lock;
Поток записи
write_seqlock(lock); time=…;
write_sequnlock(lock)
;
Поток чтения
unsigned long seq;
seq = read_seqbegin(lock);
//считываем время
} while(read_seqretry(&lock,seq));
Реализация seqlock
Spinlock l; |
Read_seqbegin(){ |
Counter c; |
return c; |
|
} |
write_seqlock(){ |
|
lock(l); |
Read_seqretry(int iv){ |
c++ |
return (iv & 1) | (c^ iv); |
} |
} |
write_sequnlock(){ |
|
c++ |
|
unlock(l); |
|
} |
|
Недостатки spinlock
Занимают процессорное время
Не могут использоваться для длительного времени ожидания
Семафоры
Семафоры – целочисленные переменные с которыми возможно выполнять атомарные операции увеличения/уменьшения на 1
Если значение семафора становится меньшем нуля, то процесс, который выполнил такую операцию блокируется, пока значение семафора не станет большим или равным нулю
Процессы, ожидающие освобождения семафора не занимают процессорное время
Операции с семафорами
Присвоение значения
Подъем (увеличение на 1) – up()
Опускание (уменьшение на 1) – down()
Требование нулевого значение (есть не во всех реализациях) test()
Считывание значение read()
Все операции атомарные