
- •Алгоритмы
- •План
- •Литература
- •Необходимость
- •Пример: файл данных
- •Критические участки
- •Взаимоисключающий
- •Атомарные операции
- •Пример: вставка в
- •Синхронизация в системах с общей памятью
- •Атомарные операции с общей памятью
- •Блокировки
- •Захват и освобождение блокировок
- •Обеспечение атомарности с помощью блокировки
- •Предотвращение состояний конкуренции
- •Взаимоблокировка
- •Самоблокировка
- •Предотвращение
- •Еще раз о состоянии конкуренции
- •Спин-блокировки
- •Спин блокировка с атомарными операциями
- •Блокировки без атомарных операций
- •Свойства
- •Доказательство
- •Доказательство отсутствия бесконечного ожидания
- •Алгоритмы для N процессоров
- •Блокировка в состоянии конфликта
- •Эффективность блокировок
- •Спин-блокировки для реальных систем
- •Блокировки чтения-записи
- •Пример использования блокировки чтения-записи
- •Пример реализации rw блокировки
- •Отказ обслуживания записи при обслуживании чтения
- •Блокировки чтения-записи с приоритетом на запись
- •Использование секвентных блокировок
- •Реализация seqlock
- •Недостатки spinlock
- •Семафоры
- •Операции с семафорами
- •Mutex
- •Пример:
- •Счетный семафор
- •Реализация семафоров
- •Пример реализации семафора
- •Семафоры чтения записи
- •Особенности семафоров
- •Условные переменные
- •Пример использование
- •Мониторы
- •Барьер
- •Блокировки в системах с распределенной памятью
- •Пример реализации барьера
- •Вопросы?

Спин-блокировки
Спин-блокировка – использование бесконечного цикла (вращения) для проверки условия возможности доступа к ресурсу
Самый быстрый тип блокировки
Используется, когда время выполнения критической секции мало
Постоянно занимают процессор

Спин блокировка с атомарными операциями
Test-and-set lock
Атомарная машинная инструкция tas(addr,val)
Атомарно считывает предыдущее значение из области памяти addr и устанавливает значение этой области памяти в val
static int lock_var=0;
void lock(int* var){ while(tas(var,1));
}
void unlock(int* var){ *var=0;
//или //atomic_set(var,0);
}

Блокировки без атомарных операций
Используются
последовательные операции записи, чтения, проверки нескольких переменных
Алгоритм Петерсона
Два процессора 0 и 1
me() – номер текущего процессора
Три общих переменных
Flag[2] – кто ожидает
Victim – кто захватывает
int flag[2]={0,0}; Int victim;
void lock(){ flag[me()]=1; victim = me();
while(flag[!me()] && victim==me());
}
void unlock(){ flag[me()]=0;
}

Свойства
Алгоритм Петерсона обеспечивает взаимоисключающий доступ к критическому разделу
Алгоритм Петерсона гарантирует отсутствие бесконечного ожидания

Доказательство
взаимоисключенияЗапишем последовательность действий обоих процессоров
Запись0(flag[0]=1)->запись0(victim=0) ->чтение0(flag[1])->чтение0(victim)
Запись1(flag[1]=1)->запись1(victim=1) ->чтение1(flag[0])->чтение1(victim)
Допустим, что оба процессора вошли в критический раздел
Пусть для определенности процессор 0 записал значение переменной victim последним
Все значения flag[] уже записаны
Тогда последовательность записи этой переменной была следующей
запись1(victim=1)->запись0(victim=0)
Раз процессор 0 вошел в критический раздел, то он прочитал
flag[1]=0, victim=0
Значит последовательность операций была
запись0(victim=0)-> чтение1(flag[1]==0)
Учитывая первые 3 уравнения
Запись1(flag[1]=1)->запись1(victim=1) ->запись0(victim=0)->чтение1(flag[1]==0)
Получается, что значение переменной flag[1] поменялось после записи victim, а такого не может быть

Доказательство отсутствия бесконечного ожидания
Пусть процессор 0 бесконечно ожидает в цикле, тогда flag[1]=1 и victim=0
Такая ситуация может возникнуть только
когда процессор 1 выполнил команду flag[me()]=1; и еще не выполнил команду
victim = me();
Эти две команды идут подряд, поэтому, если выполнилась первая, то вторая тоже скоро выполнится

Алгоритмы для N процессоров
Более сложные
Используется следующий принцип:
Каждому процессору, которые ожидают на захват блокировки назначается уникальная комбинация его номера и целочисленной метки
Только для одного процессора его комбинация номер-метка позволяет войти в критический раздел

Блокировка в состоянии конфликта
Спин-блокировка - сложный алгоритм, который выполняется несколькими процессами одновременно
Когда за захват блокировки состязаются потоки – блокировка находится в состоянии конфликта (contended)
Различные алгоритмы требуют разного количества операций при обработке состояния конфликта при большом количестве потоков

Эффективность блокировок
Существуют алгоритмы порядка O(n2) и O(n) операций для выполнения проверок в состоянии конфликта
При увеличении количества потоков время выполнения может расти из-за конфликтов при захвате

Спин-блокировки для реальных систем
Атомарные операции – медленные
Запись в общую память может выполняться не сразу, а буферизироваться процессором
Компилятор может пытаться оптимизировать код и изменять порядок операций
Необходимо использовать барьеры памяти, компилятора
Существует множество библиотечных функций для обеспечения блокировок