SlideShare uma empresa Scribd logo
1 de 38
Операционные Системы
5. Синхронизация
Брагин Алексей Владимирович
aleksey@reactos.org
ИУ9, МГТУ им. Н.Э. Баумана
Критические секции
• Последовательность инструкций,
одновременное выполнение которой может
привести к неправильным результатам
называется критической секцией
• Т.о. взаимное исключение (mutual exclusion)
между двумя критическими секциями
достаточно для корректного исполнения
• Один из способов гарантировать взаимное
исключение – использовать блокировки (locks)
© 2013 Брагин А.В. 2
Пример КС
© 2013 Брагин А.В. 3
Поток1 Поток2 Поток1 Поток2 Поток1 Поток2
Некорректно Правильно Правильно
Критические секции 2
• В каких случаях возникают критические
секции?
– В одновременно выполняемом коде
– Действия прочитать-изменить-записать
– Общая переменная
• Общие переменные
– Глобальные и выделенные из кучи переменные
– Любые другие не локальные переменные в
стэке
© 2013 Брагин А.В. 4
Классический пример
• Функция снятия денег со счёта фирмы в банке
(использовать только для своих счетов!)
• Предположим, что одновременно происходит
выплата заработной платы 10000руб. с одного
счёта двум сотрудникам. А на счету находится
100 000 руб.
© 2013 Брагин А.В. 5
void WithdrawMoney(account, amount) {
int balance = GetBalance(account); // чтение
balance -= amount; // изменение
SetBalance(account, balance); // запись
GiveCashToUser();
}
Классический пример 2
• Программа в банке работает в
многопоточном режиме
© 2013 Брагин А.В. 6
void WithdrawMoney(account, amount) {
int balance = GetBalance(account);
balance -= amount;
SetBalance(account, balance);
GiveCashToUser();
}
void WithdrawMoney(account, amount) {
int balance = GetBalance(account);
balance -= amount;
SetBalance(account, balance);
GiveCashToUser();
}
Классический пример 3
• Если многозадачность вытесняющая, то
переключение контекста может произойти
в любом месте
• Гарантировать, что три операции пройдут в
нужной последовательности нельзя
• Даже такой простой код, как k++ не
является безопасным! (если k – общая
переменная)
© 2013 Брагин А.В. 7
Требования к критическим секциям
• Каким требованиям должна удовлетворять
правильная реализация критических секций
– Взаимное исключение
• Максимум один поток может быть в критической секции
• Другой поток вне критической секции не может
вытеснить поток, находящийся в критической секции
– Ограниченное ожидание
• Если поток ожидает входа в критическую секцию, то рано
или поздно это произойдёт
– Производительность
• Накладные расходы на вход и выход из критических
секций малы по сравнению с работой, выполняемой
внутри критических секций
© 2013 Брагин А.В. 8
Механизмы реализации КС
• Запрет прерываний
– Самый простой, но очень много недостатков
• Алгоритм Петерсона
• Спинлоки (spinlocks)
– Базовый примитив, часто используется для построения более сложных
блокировок
• Семафоры (non-spinning locks)
– Просты для понимания, но сложны в использовании
• Мониторы
– Высокоуровневая блокировка, требует поддержки со стороны языка
программирования
– Легче использовать
• Сообщения
– Простая модель взаимодействия и синхронизации на основе
передаваемых сообщений через канал
– Используется преимущественно в распределённых системах
© 2013 Брагин А.В. 9
Запрет прерываний
• Простейший подход: временно отключить
прерывания
• Недостатки:
– Доступно только ядру, режим пользователя не
может отключать прерывания
– Недостаточно на многопроцессорной системе (у
каждого ЦП – свои прерывания)
– Длительный период отключения прерываний
может привести к неработоспособности устройств
• Используется только в редких случаях
© 2013 Брагин А.В. 10
Алгоритм Петерсона
• Работает для ограниченного числа процессов N (пример для 2)
• Не требует аппаратной поддержки атомарных операций
© 2013 Брагин А.В. 11
// Code based on Figure 2-24. Peterson’s solution for achieving mutual
// exclusion (Tannenbaum, 2007, p. 123). Fixed by me.
int turn; // Чья очередь?
int interested[2]; // Исходно все значения равны FALSE
void EnterRegion(int process) // process – число от 0 до N-1
{
int other = 1 – process; // Номер второго процесса
interested[process] = TRUE; // Обозначение интереса о входе
turn = process; // Установка флага
while (turn == process && interested[other]); // Ожидание
}
void LeaveRegion(int process) // process, который выходит из КС
{
interested[process] = FALSE; // Сообщаем о выходе из КС
}
Блокировки/защёлки (locks)
• Защёлка – это объект с двумя операциями
– Lock(): т.е. войти в крит. секцию
– Unlock(): выйти из крит. секции
• Lock() блокирует дальнейшее выполнение
потока до тех пор, пока не будет выполнен
вход в крит. секцию
• Можно сказать, что поток держит эту
защёлку, а потом освобождает её.
© 2013 Брагин А.В. 12
Как работает защёлка
© 2013 Брагин А.В. 13
Поток1 Поток2
Lock()
Unlock()
Unlock()
Lock()
Пример с банком и защёлкой
© 2013 Брагин А.В. 14
void WithdrawMoney(account, amount) {
Lock(globalLock);
int balance = GetBalance(account); // чтение
balance -= amount; // изменение
SetBalance(account, balance); // запись
Unlock(globalLock);
GiveCashToUser();
}
Спинлок
• Циклическая блокировка, необходима
аппаратная реализация
• Test-and-set
• Почему аппаратная?
© 2013 Брагин А.В. 15
typedef struct spinlock_s {
int acquired = 0;
} spinlock_t;
void Lock(spinlock_t *s) {
while (s->acquired);
s->acquired = 1;
}
void Unlock(spinlock_t *s)
{
s->acquired = 0;
}
Реализация спинлока
• Внутри спинлока есть критическая секция
• Блокировка/разблокировка должна быть
атомарной операцией
– Атомарная – выполняется без прерывания,
либо всё, либо ничего
• Поэтому нужна аппаратная поддержка
– Специальные инструкции: test-and-set,
compare-and-swap
– Временное отключение прерываний
© 2013 Брагин А.В. 16
Аппаратный test-and-set
• Внутри ЦП реализована следующая
атомарная операция:
© 2013 Брагин А.В. 17
int TestAndSet(int *Val) {
int OldValue = *Val;
*Val = 1;
return OldValue;
}
Реализация спинлока 2
• Используя такую аппаратную инструкцию,
новая реализация спинлока:
© 2013 Брагин А.В. 18
typedef struct spinlock_s {
int acquired = 0;
} spinlock_t;
void Lock(spinlock_t *s) {
while (TestAndSet(&s->acquired));
}
void Unlock(spinlock_t *s) {
s->acquired = 0;
}
Проблемы спинлока
• Неэффективны: если поток заблокирован
спинлоком, то будет находиться в цикле до
окончания кванта времени
• Спинлоки – примитивы для более
высокоуровневой синхронизации
© 2013 Брагин А.В. 19
Высокоуровневая синхронизация
• Семафоры
• Мониторы (ещё одно значение слова
монитор…)
• Тупиковые ситуации (deadlock)
© 2013 Брагин А.В. 20
Семафоры
• Изобретатель – Dijkstra (Нидерланды), в 1968
году.
• Более высокий уровень абстракции, чем
защёлки
• Семафор, это переменная, которой можно
управлять с помощью двух операций:
– P(sem) – ожидать, пока sem не станет больше 0,
затем уменьшить sem на 1 и продолжить
– V(sem) – увеличить sem на 1.
• P() и V()? P() это Wait(), а V() это Signal() ?!
© 2013 Брагин А.В. 21
Семафоры 2
• Всё объясняется происхождением
происхождением Дейкстры
• Probeer (нидерл.) – пробовать
• Verhoog (нидерл.) – увеличивать
• Важно запомнить:
– Перед verhoog’ом нужно probeer’овать! И
наоборот.
© 2013 Брагин А.В. 22
Семафоры 3
• У каждого семафора есть ассоциированная с ним
очередь потоков
• Когда поток вызывает P(sem)
– Если семафор доступен (т.е. > 0), то уменьшить sem и
вернуть управление потоку
– Если семафор недоступен (0), то поместить поток в
соответствующую очередь, и дать управление другому
потоку
• Когда поток вызывает V(sem)
– Если есть потоки в очереди (ожидающие семафора),
разблокировать один из них. Если это тот же, который
вызвал V – просто передать ему управление
– Если нет ожидающих, то просто увеличить sem на 1
© 2013 Брагин А.В. 23
Два типа семафоров
• Бинарный (мьютексный) семафор
– sem исходно = 1
– Гарантирует взаимноисключающий доступ к ресурсу
(напр., критической секции кода)
– Только один поток/процесс может захватить ресурс
– Логически эквивалентен защёлке с блокировкой, а не
спинлоку
• Считающий семафор
– Исходно sem равно N, где N – число единиц ресурса
(или потоков, которые могут использовать эти ресурсы)
– Одновременно до N поток могут захватывать ресурс
© 2013 Брагин А.В. 24
Проблемы
• Семафоры, блокировки и условные переменные – какие
проблемы?
• Они могут быть использованы для решения
традиционных задач синхронизации, но легко
совершить ошибки
– По-сути это глобальные переменные с общим доступом
– Нет связи между этими переменными и данными, доступом
к которым они управляют
– Нет контроля за их использованием
• Условные переменные – будет ли сигнал вообще?
• Семафоры – будет ли V()?
• Защёлки – был ли вызван Lock() в нужное время. А Unlock()? Или
вообще ничего не было вызвано?
• Поэтому, появляются ошибки. Нужна поддержка в
языке.
© 2013 Брагин А.В. 25
Монитор
• Ещё один подход к синхронизации
• Монитор – это конструкция языка программирования, которая
поддерживает контролируемый доступ к общим данным
• Код синхронизации добавляется компилятором
• Монитор – это класс, в котором каждый метод автоматически
выполняет Lock() при входе в метод, и Unlock() при выходе из него
• Поэтому он объединяет
– Общие структуры данных
– Процедуры, работающие над этими данными (методы объекта)
– Синхронизацию между потоками, вызывающими эти процедуры
• Доступ к данным может быть только из монитора, используя его
процедуры
– Защита доступа
– Точное понимание какие данные защищены монитором
• Решает ключевые проблемы семафоров
© 2013 Брагин А.В. 26
Монитор 2
© 2013 Брагин А.В. 27
Общие данные
Очередь ожидания потоков,
пытающихся войти в монитор
операции (методы)В один момент
времени в
мониторе только
один поток
Процедура A
Процедура B
Процедура C
Этот
прямоугольник
не обязательно
один процесс!
Рисунок из лекций Gribble, Lazowska, Levy, Zahorjan,
университет Washington, США.
Мониторы и Java
• Java предоставляет синхронизацию, схожую
с монитором. Но в полной мере это не
мониторы.
• У каждого Java объекта есть защёлка
• Ключевое слово synchronized захватывает
эту защёлку
• Может применяться к отдельным методам
или целым блокам кода
© 2013 Брагин А.В. 28
Тупиковая ситуация
• Или «взаимная блокировка». Одно
английское слово - deadlock
• Поток находится в тупике, если он ожидает
события, которое никогда не произойдёт
• Пример:
– Поток А в КС 1, ожидает доступа к КС 2; Поток Б
в КС 2, ожидает доступа к КС 1
© 2013 Брагин А.В. 29
Четыре условия тупика
1. Взаимное исключение
2. Взять и ждать
3. Нет вытеснения
4. Круговое ожидание
• Соответственно, нарушив одно из этих
условий можно избежать тупика
© 2013 Брагин А.В. 30
Граф ресурсов
• Граф распределения ресурсов (граф ожидания) –
это способ визуализации состояния потоков для
определения ситуаций взаимной блокировки
• Две доли графа
– Вершины T соответствуют потокам или транзакциям
(напр. в случае СУБД)
– Вершины R соответствуют ресурсам, которые могут
быть захвачены потоками
• Дуги
– От ресурса к потоку – поток владеет ресурсом
– От потока к ресурсу – поток освобождает ресурс
© 2013 Брагин А.В. 31
Взаимная блокировка на графе
• Взаимная блокировка в том случае, если в
графе есть нередуцируемые циклы
© 2013 Брагин А.В. 32
T1 T2
R2
R1
R1 захвачен потоком
Поток ожидает R1
R2 захвачен потоком
Поток ожидает R2
Обработка тупиковых ситуаций
• Либо исключить одно из четырёх условий
тупика
– Взаимное исключение – это-то точно нельзя убрать
– Удержание и ожидание
– Отсутствие принудительного освобождения
ресурсов
– Циклическое ожидание
• Обработку можно классифицировать на
– Предотвращение тупиков
– Избежание тупиков
– Обнаружение и восстановление
© 2013 Брагин А.В. 33
Предотвращение
• Программы должны придерживаться строгих
правил для того, чтобы гарантированно избежать
взаимной блокировки
• Устранение «удержания и ожидания»
– Каждый поток вначале получает все ресурсы
– Заблокирован пока все ресурсы не освободятся
• Устранение циклического ожидания
– Ресурсы пронумерованы
– Каждый поток захватывает ресурс в порядке номеров.
Если ему нужно захватить ресурс № k, то даже если ему
ненужны ресурсы [0,k) он их всё равно захватит
© 2013 Брагин А.В. 34
Избежание
• Менее строгие ограничения
• Устранение циклического ожидания
– Каждый поток устанавливает свою
максимальную потребность для каждого типа
ресурсов
– При каждом запросе о выделении ресурса
система выполняет алгоритм банкира
© 2013 Брагин А.В. 35
Обнаружение и восстановление
• В некоторый момент времени проверять,
есть ли в системе тупиковая ситуация
• Если есть, то предпринять действия к
разрешению тупиковой ситуации
© 2013 Брагин А.В. 36
Практика в СУБД
• Microsoft SQL Server. Автоматически
обнаруживает ситуации взаимной
блокировки. Ядро СУБД выбирает одну из
заблокированных сессий в качестве
«жертвы» и выполняет принудительное её
завершение с ошибкой
• Oracle. То же, что и MSSQL, но с
дополнительными «наворотами».
© 2013 Брагин А.В. 37
Практика в ОС
• Применительно к Windows (и Linux тоже)
– Многопоточное реентерабельное ядро
предоставляет большие возможности взаимной
блокировки…
– Оригинально, в ранних версиях NT были
предусмотрены многоуровневые мьютексы, от
которых впоследствии были вынуждены
отказаться….
– TL;DR: В ядрах ОС есть обнаружение взаимных
блокировок. Фундаментально проблема
избежания тупиков в ядрах ОС на практике не
решается.
© 2013 Брагин А.В. 38

Mais conteúdo relacionado

Mais procurados

Os detection with arp
Os detection with arpOs detection with arp
Os detection with arp
David Clark
 

Mais procurados (20)

Metodologia SCRUM
Metodologia SCRUMMetodologia SCRUM
Metodologia SCRUM
 
Clang: More than just a C/C++ Compiler
Clang: More than just a C/C++ CompilerClang: More than just a C/C++ Compiler
Clang: More than just a C/C++ Compiler
 
O que acontece quando limitamos o WIP (Work In Progress)?
O que acontece quando limitamos o WIP (Work In Progress)?O que acontece quando limitamos o WIP (Work In Progress)?
O que acontece quando limitamos o WIP (Work In Progress)?
 
Paradigmas de Programação - Imperativo, Orientado a Objetos e Funcional
Paradigmas de Programação - Imperativo, Orientado a Objetos e FuncionalParadigmas de Programação - Imperativo, Orientado a Objetos e Funcional
Paradigmas de Programação - Imperativo, Orientado a Objetos e Funcional
 
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
MCA Daemon: Hybrid Throughput Analysis Beyond Basic BlocksMCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
 
Fluxo de Processos do Guia PMBOK® – 6ª Edição
Fluxo de Processos do Guia PMBOK® – 6ª EdiçãoFluxo de Processos do Guia PMBOK® – 6ª Edição
Fluxo de Processos do Guia PMBOK® – 6ª Edição
 
Scrum em 15 minutos
Scrum em 15 minutosScrum em 15 minutos
Scrum em 15 minutos
 
Built in physical and logical replication in postgresql-Firat Gulec
Built in physical and logical replication in postgresql-Firat GulecBuilt in physical and logical replication in postgresql-Firat Gulec
Built in physical and logical replication in postgresql-Firat Gulec
 
Azure Spring Cloud Workshop - June 17, 2020
Azure Spring Cloud Workshop - June 17, 2020Azure Spring Cloud Workshop - June 17, 2020
Azure Spring Cloud Workshop - June 17, 2020
 
All your SAP passwords belong to us
All your SAP passwords belong to usAll your SAP passwords belong to us
All your SAP passwords belong to us
 
Process hollowing
Process hollowingProcess hollowing
Process hollowing
 
Introdução a Framework Flask
Introdução a Framework FlaskIntrodução a Framework Flask
Introdução a Framework Flask
 
Os detection with arp
Os detection with arpOs detection with arp
Os detection with arp
 
USENIX ATC 2017: Visualizing Performance with Flame Graphs
USENIX ATC 2017: Visualizing Performance with Flame GraphsUSENIX ATC 2017: Visualizing Performance with Flame Graphs
USENIX ATC 2017: Visualizing Performance with Flame Graphs
 
Kanban
KanbanKanban
Kanban
 
Overview of the ehcache
Overview of the ehcacheOverview of the ehcache
Overview of the ehcache
 
Gestão ágil do portfólio
Gestão ágil do portfólioGestão ágil do portfólio
Gestão ágil do portfólio
 
256557462 un1 apostila unip-pdf
256557462 un1 apostila unip-pdf256557462 un1 apostila unip-pdf
256557462 un1 apostila unip-pdf
 
Burpで指定文字列を検索
Burpで指定文字列を検索Burpで指定文字列を検索
Burpで指定文字列を検索
 
Agile SCRUM
Agile SCRUMAgile SCRUM
Agile SCRUM
 

Semelhante a Операционные системы 2015, лекция № 5

Проблематика создания OpenFlow контроллеров для SDN
Проблематика создания OpenFlow контроллеров для SDNПроблематика создания OpenFlow контроллеров для SDN
Проблематика создания OpenFlow контроллеров для SDN
ARCCN
 
04 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_104 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_1
921519
 
2014.12.23 Александр Андреев, Parallels
2014.12.23 Александр Андреев, Parallels2014.12.23 Александр Андреев, Parallels
2014.12.23 Александр Андреев, Parallels
Nikolay Samokhvalov
 
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
Ontico
 
Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)
Dmitry Tsitelov
 
Dz Java Hi Load 0.4
Dz Java Hi Load 0.4Dz Java Hi Load 0.4
Dz Java Hi Load 0.4
HighLoad2009
 

Semelhante a Операционные системы 2015, лекция № 5 (20)

Lab5
Lab5Lab5
Lab5
 
Atomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAtomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithms
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Алексей Федоров
Алексей ФедоровАлексей Федоров
Алексей Федоров
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)
 
Проблематика создания OpenFlow контроллеров для SDN
Проблематика создания OpenFlow контроллеров для SDNПроблематика создания OpenFlow контроллеров для SDN
Проблематика создания OpenFlow контроллеров для SDN
 
Универсальная методика поиска неисправностей от Cisco TAC Игорь Тумкин
Универсальная методика поиска неисправностей от Cisco TAC Игорь ТумкинУниверсальная методика поиска неисправностей от Cisco TAC Игорь Тумкин
Универсальная методика поиска неисправностей от Cisco TAC Игорь Тумкин
 
Масштабируемая архитектура фронтенда
Масштабируемая архитектура фронтендаМасштабируемая архитектура фронтенда
Масштабируемая архитектура фронтенда
 
Dev collaboration
Dev collaborationDev collaboration
Dev collaboration
 
Кружок по робототехнике. Занятие #8. Решение задач
Кружок по робототехнике. Занятие #8. Решение задачКружок по робототехнике. Занятие #8. Решение задач
Кружок по робототехнике. Занятие #8. Решение задач
 
Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?
 
04 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_104 ос взаимодействие_процессов_1
04 ос взаимодействие_процессов_1
 
2014.12.23 Александр Андреев, Parallels
2014.12.23 Александр Андреев, Parallels2014.12.23 Александр Андреев, Parallels
2014.12.23 Александр Андреев, Parallels
 
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GIL
 
SETCON'18 - Dzmitry Nichyparuk - Designing reliable software
SETCON'18 - Dzmitry Nichyparuk - Designing reliable softwareSETCON'18 - Dzmitry Nichyparuk - Designing reliable software
SETCON'18 - Dzmitry Nichyparuk - Designing reliable software
 
Nonblocking algorithms/CAS/Atomics by Alexey Fyodorov
Nonblocking algorithms/CAS/Atomics by Alexey FyodorovNonblocking algorithms/CAS/Atomics by Alexey Fyodorov
Nonblocking algorithms/CAS/Atomics by Alexey Fyodorov
 
Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)
 
Dz Java Hi Load 0.4
Dz Java Hi Load 0.4Dz Java Hi Load 0.4
Dz Java Hi Load 0.4
 

Mais de Aleksey Bragin

Mais de Aleksey Bragin (8)

Информационная безопасность в открытых проектах (РИФ 2015)
Информационная безопасность в открытых проектах (РИФ 2015) Информационная безопасность в открытых проектах (РИФ 2015)
Информационная безопасность в открытых проектах (РИФ 2015)
 
Обратные фьючерсы в биткойнах
Обратные фьючерсы в биткойнахОбратные фьючерсы в биткойнах
Обратные фьючерсы в биткойнах
 
Операционные системы 2015, лекция № 7
Операционные системы 2015, лекция № 7Операционные системы 2015, лекция № 7
Операционные системы 2015, лекция № 7
 
Операционные системы 2015, лекция № 6
Операционные системы 2015, лекция № 6Операционные системы 2015, лекция № 6
Операционные системы 2015, лекция № 6
 
Операционные системы 2015, лекция № 3
Операционные системы 2015, лекция № 3Операционные системы 2015, лекция № 3
Операционные системы 2015, лекция № 3
 
Операционные системы 2015, лекция № 2
Операционные системы 2015, лекция № 2Операционные системы 2015, лекция № 2
Операционные системы 2015, лекция № 2
 
Операционные системы 2015, лекция № 1
Операционные системы 2015, лекция № 1Операционные системы 2015, лекция № 1
Операционные системы 2015, лекция № 1
 
ReactOS Tech Talk (ВМК МГУ, ИСП РАН)
ReactOS Tech Talk (ВМК МГУ, ИСП РАН)ReactOS Tech Talk (ВМК МГУ, ИСП РАН)
ReactOS Tech Talk (ВМК МГУ, ИСП РАН)
 

Операционные системы 2015, лекция № 5

  • 1. Операционные Системы 5. Синхронизация Брагин Алексей Владимирович aleksey@reactos.org ИУ9, МГТУ им. Н.Э. Баумана
  • 2. Критические секции • Последовательность инструкций, одновременное выполнение которой может привести к неправильным результатам называется критической секцией • Т.о. взаимное исключение (mutual exclusion) между двумя критическими секциями достаточно для корректного исполнения • Один из способов гарантировать взаимное исключение – использовать блокировки (locks) © 2013 Брагин А.В. 2
  • 3. Пример КС © 2013 Брагин А.В. 3 Поток1 Поток2 Поток1 Поток2 Поток1 Поток2 Некорректно Правильно Правильно
  • 4. Критические секции 2 • В каких случаях возникают критические секции? – В одновременно выполняемом коде – Действия прочитать-изменить-записать – Общая переменная • Общие переменные – Глобальные и выделенные из кучи переменные – Любые другие не локальные переменные в стэке © 2013 Брагин А.В. 4
  • 5. Классический пример • Функция снятия денег со счёта фирмы в банке (использовать только для своих счетов!) • Предположим, что одновременно происходит выплата заработной платы 10000руб. с одного счёта двум сотрудникам. А на счету находится 100 000 руб. © 2013 Брагин А.В. 5 void WithdrawMoney(account, amount) { int balance = GetBalance(account); // чтение balance -= amount; // изменение SetBalance(account, balance); // запись GiveCashToUser(); }
  • 6. Классический пример 2 • Программа в банке работает в многопоточном режиме © 2013 Брагин А.В. 6 void WithdrawMoney(account, amount) { int balance = GetBalance(account); balance -= amount; SetBalance(account, balance); GiveCashToUser(); } void WithdrawMoney(account, amount) { int balance = GetBalance(account); balance -= amount; SetBalance(account, balance); GiveCashToUser(); }
  • 7. Классический пример 3 • Если многозадачность вытесняющая, то переключение контекста может произойти в любом месте • Гарантировать, что три операции пройдут в нужной последовательности нельзя • Даже такой простой код, как k++ не является безопасным! (если k – общая переменная) © 2013 Брагин А.В. 7
  • 8. Требования к критическим секциям • Каким требованиям должна удовлетворять правильная реализация критических секций – Взаимное исключение • Максимум один поток может быть в критической секции • Другой поток вне критической секции не может вытеснить поток, находящийся в критической секции – Ограниченное ожидание • Если поток ожидает входа в критическую секцию, то рано или поздно это произойдёт – Производительность • Накладные расходы на вход и выход из критических секций малы по сравнению с работой, выполняемой внутри критических секций © 2013 Брагин А.В. 8
  • 9. Механизмы реализации КС • Запрет прерываний – Самый простой, но очень много недостатков • Алгоритм Петерсона • Спинлоки (spinlocks) – Базовый примитив, часто используется для построения более сложных блокировок • Семафоры (non-spinning locks) – Просты для понимания, но сложны в использовании • Мониторы – Высокоуровневая блокировка, требует поддержки со стороны языка программирования – Легче использовать • Сообщения – Простая модель взаимодействия и синхронизации на основе передаваемых сообщений через канал – Используется преимущественно в распределённых системах © 2013 Брагин А.В. 9
  • 10. Запрет прерываний • Простейший подход: временно отключить прерывания • Недостатки: – Доступно только ядру, режим пользователя не может отключать прерывания – Недостаточно на многопроцессорной системе (у каждого ЦП – свои прерывания) – Длительный период отключения прерываний может привести к неработоспособности устройств • Используется только в редких случаях © 2013 Брагин А.В. 10
  • 11. Алгоритм Петерсона • Работает для ограниченного числа процессов N (пример для 2) • Не требует аппаратной поддержки атомарных операций © 2013 Брагин А.В. 11 // Code based on Figure 2-24. Peterson’s solution for achieving mutual // exclusion (Tannenbaum, 2007, p. 123). Fixed by me. int turn; // Чья очередь? int interested[2]; // Исходно все значения равны FALSE void EnterRegion(int process) // process – число от 0 до N-1 { int other = 1 – process; // Номер второго процесса interested[process] = TRUE; // Обозначение интереса о входе turn = process; // Установка флага while (turn == process && interested[other]); // Ожидание } void LeaveRegion(int process) // process, который выходит из КС { interested[process] = FALSE; // Сообщаем о выходе из КС }
  • 12. Блокировки/защёлки (locks) • Защёлка – это объект с двумя операциями – Lock(): т.е. войти в крит. секцию – Unlock(): выйти из крит. секции • Lock() блокирует дальнейшее выполнение потока до тех пор, пока не будет выполнен вход в крит. секцию • Можно сказать, что поток держит эту защёлку, а потом освобождает её. © 2013 Брагин А.В. 12
  • 13. Как работает защёлка © 2013 Брагин А.В. 13 Поток1 Поток2 Lock() Unlock() Unlock() Lock()
  • 14. Пример с банком и защёлкой © 2013 Брагин А.В. 14 void WithdrawMoney(account, amount) { Lock(globalLock); int balance = GetBalance(account); // чтение balance -= amount; // изменение SetBalance(account, balance); // запись Unlock(globalLock); GiveCashToUser(); }
  • 15. Спинлок • Циклическая блокировка, необходима аппаратная реализация • Test-and-set • Почему аппаратная? © 2013 Брагин А.В. 15 typedef struct spinlock_s { int acquired = 0; } spinlock_t; void Lock(spinlock_t *s) { while (s->acquired); s->acquired = 1; } void Unlock(spinlock_t *s) { s->acquired = 0; }
  • 16. Реализация спинлока • Внутри спинлока есть критическая секция • Блокировка/разблокировка должна быть атомарной операцией – Атомарная – выполняется без прерывания, либо всё, либо ничего • Поэтому нужна аппаратная поддержка – Специальные инструкции: test-and-set, compare-and-swap – Временное отключение прерываний © 2013 Брагин А.В. 16
  • 17. Аппаратный test-and-set • Внутри ЦП реализована следующая атомарная операция: © 2013 Брагин А.В. 17 int TestAndSet(int *Val) { int OldValue = *Val; *Val = 1; return OldValue; }
  • 18. Реализация спинлока 2 • Используя такую аппаратную инструкцию, новая реализация спинлока: © 2013 Брагин А.В. 18 typedef struct spinlock_s { int acquired = 0; } spinlock_t; void Lock(spinlock_t *s) { while (TestAndSet(&s->acquired)); } void Unlock(spinlock_t *s) { s->acquired = 0; }
  • 19. Проблемы спинлока • Неэффективны: если поток заблокирован спинлоком, то будет находиться в цикле до окончания кванта времени • Спинлоки – примитивы для более высокоуровневой синхронизации © 2013 Брагин А.В. 19
  • 20. Высокоуровневая синхронизация • Семафоры • Мониторы (ещё одно значение слова монитор…) • Тупиковые ситуации (deadlock) © 2013 Брагин А.В. 20
  • 21. Семафоры • Изобретатель – Dijkstra (Нидерланды), в 1968 году. • Более высокий уровень абстракции, чем защёлки • Семафор, это переменная, которой можно управлять с помощью двух операций: – P(sem) – ожидать, пока sem не станет больше 0, затем уменьшить sem на 1 и продолжить – V(sem) – увеличить sem на 1. • P() и V()? P() это Wait(), а V() это Signal() ?! © 2013 Брагин А.В. 21
  • 22. Семафоры 2 • Всё объясняется происхождением происхождением Дейкстры • Probeer (нидерл.) – пробовать • Verhoog (нидерл.) – увеличивать • Важно запомнить: – Перед verhoog’ом нужно probeer’овать! И наоборот. © 2013 Брагин А.В. 22
  • 23. Семафоры 3 • У каждого семафора есть ассоциированная с ним очередь потоков • Когда поток вызывает P(sem) – Если семафор доступен (т.е. > 0), то уменьшить sem и вернуть управление потоку – Если семафор недоступен (0), то поместить поток в соответствующую очередь, и дать управление другому потоку • Когда поток вызывает V(sem) – Если есть потоки в очереди (ожидающие семафора), разблокировать один из них. Если это тот же, который вызвал V – просто передать ему управление – Если нет ожидающих, то просто увеличить sem на 1 © 2013 Брагин А.В. 23
  • 24. Два типа семафоров • Бинарный (мьютексный) семафор – sem исходно = 1 – Гарантирует взаимноисключающий доступ к ресурсу (напр., критической секции кода) – Только один поток/процесс может захватить ресурс – Логически эквивалентен защёлке с блокировкой, а не спинлоку • Считающий семафор – Исходно sem равно N, где N – число единиц ресурса (или потоков, которые могут использовать эти ресурсы) – Одновременно до N поток могут захватывать ресурс © 2013 Брагин А.В. 24
  • 25. Проблемы • Семафоры, блокировки и условные переменные – какие проблемы? • Они могут быть использованы для решения традиционных задач синхронизации, но легко совершить ошибки – По-сути это глобальные переменные с общим доступом – Нет связи между этими переменными и данными, доступом к которым они управляют – Нет контроля за их использованием • Условные переменные – будет ли сигнал вообще? • Семафоры – будет ли V()? • Защёлки – был ли вызван Lock() в нужное время. А Unlock()? Или вообще ничего не было вызвано? • Поэтому, появляются ошибки. Нужна поддержка в языке. © 2013 Брагин А.В. 25
  • 26. Монитор • Ещё один подход к синхронизации • Монитор – это конструкция языка программирования, которая поддерживает контролируемый доступ к общим данным • Код синхронизации добавляется компилятором • Монитор – это класс, в котором каждый метод автоматически выполняет Lock() при входе в метод, и Unlock() при выходе из него • Поэтому он объединяет – Общие структуры данных – Процедуры, работающие над этими данными (методы объекта) – Синхронизацию между потоками, вызывающими эти процедуры • Доступ к данным может быть только из монитора, используя его процедуры – Защита доступа – Точное понимание какие данные защищены монитором • Решает ключевые проблемы семафоров © 2013 Брагин А.В. 26
  • 27. Монитор 2 © 2013 Брагин А.В. 27 Общие данные Очередь ожидания потоков, пытающихся войти в монитор операции (методы)В один момент времени в мониторе только один поток Процедура A Процедура B Процедура C Этот прямоугольник не обязательно один процесс! Рисунок из лекций Gribble, Lazowska, Levy, Zahorjan, университет Washington, США.
  • 28. Мониторы и Java • Java предоставляет синхронизацию, схожую с монитором. Но в полной мере это не мониторы. • У каждого Java объекта есть защёлка • Ключевое слово synchronized захватывает эту защёлку • Может применяться к отдельным методам или целым блокам кода © 2013 Брагин А.В. 28
  • 29. Тупиковая ситуация • Или «взаимная блокировка». Одно английское слово - deadlock • Поток находится в тупике, если он ожидает события, которое никогда не произойдёт • Пример: – Поток А в КС 1, ожидает доступа к КС 2; Поток Б в КС 2, ожидает доступа к КС 1 © 2013 Брагин А.В. 29
  • 30. Четыре условия тупика 1. Взаимное исключение 2. Взять и ждать 3. Нет вытеснения 4. Круговое ожидание • Соответственно, нарушив одно из этих условий можно избежать тупика © 2013 Брагин А.В. 30
  • 31. Граф ресурсов • Граф распределения ресурсов (граф ожидания) – это способ визуализации состояния потоков для определения ситуаций взаимной блокировки • Две доли графа – Вершины T соответствуют потокам или транзакциям (напр. в случае СУБД) – Вершины R соответствуют ресурсам, которые могут быть захвачены потоками • Дуги – От ресурса к потоку – поток владеет ресурсом – От потока к ресурсу – поток освобождает ресурс © 2013 Брагин А.В. 31
  • 32. Взаимная блокировка на графе • Взаимная блокировка в том случае, если в графе есть нередуцируемые циклы © 2013 Брагин А.В. 32 T1 T2 R2 R1 R1 захвачен потоком Поток ожидает R1 R2 захвачен потоком Поток ожидает R2
  • 33. Обработка тупиковых ситуаций • Либо исключить одно из четырёх условий тупика – Взаимное исключение – это-то точно нельзя убрать – Удержание и ожидание – Отсутствие принудительного освобождения ресурсов – Циклическое ожидание • Обработку можно классифицировать на – Предотвращение тупиков – Избежание тупиков – Обнаружение и восстановление © 2013 Брагин А.В. 33
  • 34. Предотвращение • Программы должны придерживаться строгих правил для того, чтобы гарантированно избежать взаимной блокировки • Устранение «удержания и ожидания» – Каждый поток вначале получает все ресурсы – Заблокирован пока все ресурсы не освободятся • Устранение циклического ожидания – Ресурсы пронумерованы – Каждый поток захватывает ресурс в порядке номеров. Если ему нужно захватить ресурс № k, то даже если ему ненужны ресурсы [0,k) он их всё равно захватит © 2013 Брагин А.В. 34
  • 35. Избежание • Менее строгие ограничения • Устранение циклического ожидания – Каждый поток устанавливает свою максимальную потребность для каждого типа ресурсов – При каждом запросе о выделении ресурса система выполняет алгоритм банкира © 2013 Брагин А.В. 35
  • 36. Обнаружение и восстановление • В некоторый момент времени проверять, есть ли в системе тупиковая ситуация • Если есть, то предпринять действия к разрешению тупиковой ситуации © 2013 Брагин А.В. 36
  • 37. Практика в СУБД • Microsoft SQL Server. Автоматически обнаруживает ситуации взаимной блокировки. Ядро СУБД выбирает одну из заблокированных сессий в качестве «жертвы» и выполняет принудительное её завершение с ошибкой • Oracle. То же, что и MSSQL, но с дополнительными «наворотами». © 2013 Брагин А.В. 37
  • 38. Практика в ОС • Применительно к Windows (и Linux тоже) – Многопоточное реентерабельное ядро предоставляет большие возможности взаимной блокировки… – Оригинально, в ранних версиях NT были предусмотрены многоуровневые мьютексы, от которых впоследствии были вынуждены отказаться…. – TL;DR: В ядрах ОС есть обнаружение взаимных блокировок. Фундаментально проблема избежания тупиков в ядрах ОС на практике не решается. © 2013 Брагин А.В. 38