SlideShare une entreprise Scribd logo
1  sur  68
Télécharger pour lire hors ligne
Многопоточные алгоритмы
© Роман Елизаров, Devexperts, 2014
Закон Мура и “The free lunch is over”
http://www.gotw.ca/publications/concurrency-ddj.htm
Зеленая линия =
Тысяч транзисторов
aka “Закон Мура”
Под ней =
Частота (MHz)
Нужна формальная модель параллельных
вычислений
• Чтобы доказывать:
- корректность алгоритмов
- невозможность построения тех или
иных алгоритмов
- минимально-необходимые требования
для тех или иных алгоритмов
• Для формализации отношений
между прикладным программистом
и разработчиком компилятора и
системы исполнения кода
Модель с общими объектами (общей памятью)
Поток1
Поток2
ПотокN
Общая память
Объект M
Объект 2
Объект 1
Общие объекты
• Потоки выполняют операции над общими, разделяемыми
объектами
• В этой модели не важны операции внутри потоков:
- Вычисления
- Обновления регистров процессора
- Обновления стека потока
- Обновления любой другой локальной для потока памяти
• Важна только коммуникация между потоками
• В этой модели единственный тип коммуникации между
потоками – это работа с общими объектами
Общие переменные
• Общие переменные – это просто простейший тип общего
объекта:
- У него есть значение определенного типа
- Есть операция чтения (read) и записи (write).
• Общие переменные – это базовые строительные блоки для
параллельных алгоритмов
• Модель с общими переменными – это хорошая абстракция
современных многопроцессорных систем и многопоточных ОС
- На практике, это область памяти процесса, которая
одновременно доступна для чтения и записи всем потокам,
исполняемым в данном процессе
В теоретических трудах общие переменные называют регистрами
Свойства параллельных программ
• Последовательные программы детерминированы
- Если нет явного использования случайных чисел и другого
общения с недетерминированным внешним миром
- Их свойства можно установить, анализируя последовательное
исполнение при данных входных параметрах
• Параллельные программы в общем случае
недетерминированы
- Даже если код каждого потока детерминирован
- Результат работы зависит от фактического исполнения при
данных входных параметрах
• А этих исполнений может быть много
- Говорим «программа А имеет свойство 𝑃», если программа A
имеет свойство 𝑃 при любом допустимом исполнении
Как моделировать параллельное выполнение?
• Очень простая программа. Всего два потока (P и Q), каждый из
которых последовательно выполняет 2 действия и
останавливается (3-м действием).
- У них есть общая переменная x
- Какие есть варианты вывода на экран?
thread P:
0: x = 1
1: print x
2: stop
thread Q:
0: x = 2
1: print x
2: stop
shared int x
Моделирование исполнений через чередование
операций
• 𝑆 это общее состояние:
- Состояние всех потоков
- И состояние всех общих объектов
• 𝑓 и 𝑔 это операции над объектами
- Для переменных это операции чтения
(вместе с результатом) и записи
(вместе с значением)
- Количество активных операций равно
количеству потоков
• 𝑓(𝑆) это новое состояние после
применения операции 𝑓 в состоянии 𝑆
𝑔(𝑆)𝑓(𝑆)
𝑆
𝑓 𝑔
Пример
thread P:
0: x = 1
1: print x
2: stop
thread Q:
0: x = 2
1: print x
2: stop
P0,Q0
x=0
(-, -)
P1,Q0
x=1
(-, -)
P0,Q1
x=2
(-, -)
P2,Q0
x=1
(1, -)
P1,Q1
x=2
(-, -)
P1,Q1
x=1
(-, -)
P0,Q2
x=2
(-, 2)
P2,Q2
x=2
(1, 2)
P2,Q2
x=2
(2, 2)
+1 state not shown +2 states not shown
P2,Q2
x=1
(1, 1)
+2 states not shown
P2,Q2
x=1
(2, 1)
+1 state not shown
Всего 17 состояний
shared int x
Обсуждение модели
• Эта модель не «параллельна»
- Все операции происходят последовательно (только порядок
заранее не задан)
• А на самом деле на реальных процессорах операции чтения и
записи памяти не мгновенные и происходит параллельно как
в разных ядрах так и внутри одного ядра
- В реальности процессор обменивается с памятью сообщениями
чтения/записи и таких сообщений находящихся в обработке
одновременно может быть очень много (!)
Модель чередования не отражает фактическую
реальность. Можно ли её использовать для анализа
алгоритмов на практике? Когда её можно использовать?
Физическая реальность (1)
• Свет (электромагнитные волны) в вакууме распространяется
со скоростью ~ 3 ∙ 108
м/c
- Это максимальный физический предел скорости распространения
света. В реальных материалах – медленней.
• За один такт процессора с частотой 3 ГГц (3 ∙ 109
Гц) свет в
вакууме проходит всего 10 см.
- Соседние процессоры на плате физически не могут
синхронизировать свою работу и физически не могут
определить порядок происходящих в них событиях.
- Они работают действительно параллельно.
Физическая реальность (2)
• Пусть 𝑎, 𝑏, 𝑐 ∈ 𝐸 – это физически атомарные (неделимые)
события, происходящие в пространстве-времени
- Говорим «𝑎 предшествует 𝑏» или «𝑎 произошло до 𝑏» (и
записываем 𝑎 → 𝑏), если свет от точки пространства-времени 𝑎
успевает дойти до точки пространства-времени 𝑏
- Это отношение частичного порядка на событиях
x
t
a b
Световой конус
Между 𝑎 и 𝑏 нет предшествования. Они происходят параллельно
с 𝑎 → 𝑐 и 𝑏 → 𝑐
Модель «произошло до»
• Впервые введена Л. Лампортом в 1978 году
• Исполнение системы – это пара (𝐻, → 𝐻)
- 𝐻 – это множество операций 𝑒, 𝑓, 𝑔, … (чтение и запись ячеек
памяти), произошедших во время исполнения
- «→ 𝐻» – это транзитивное, антирефлексивное, асимметричное
отношение (частичный строгий порядок) на множестве операций
- 𝑒 → 𝐻 𝑓 означает что “𝑒 произошло до 𝑓 в исполнении 𝐻”
• Чаще всего исполнение 𝐻 понятно из контекста и опускается
• Две операции 𝑒 и 𝑓 параллельны (𝑒 ∥ 𝑓) если 𝑒 ↛ 𝑓 ⋀ 𝑓 ↛ 𝑒
• Система – это набор всех возможных исполнений системы
- Говорим, что «система имеет свойство 𝑃», если каждое
исполнение системы имеет свойство 𝑃
Модель глобального времени
• В этой модели каждая операция – это временной интервал
𝑒 = 𝑡𝑖𝑛𝑣 𝑒 , 𝑡 𝑟𝑒𝑠𝑝 𝑒 где t 𝑖𝑛𝑣 𝑒 , 𝑡 𝑟𝑒𝑠𝑝(𝑒) ∈ ℝ и
𝑡
P
Q
R
𝑒
𝑓
𝑔
Будем использовать эту модель во всех иллюстрациях
Здесь:
𝑒 → f
𝑒 ∥ 𝑔
𝑓 ∥ 𝑔
𝑒 → 𝑓 ≝ 𝑡 𝑟𝑒𝑠𝑝 𝑒 < 𝑡𝑖𝑛𝑣(𝑓)
Обсуждение глобального времени
• Это всего лишь механизм, позволяющий визуализировать
факт существования параллельных операций
• При доказательстве различных фактов и анализе свойств
[исполнений] системы время не используется
- Анализируются только операции и отношения «произошло до»
На самом деле, никакого глобального
времени нет и не может быть из-за
физических ограничений
«произошло до» на практике
• Современные языки программирования предоставляют
программисту операции синхронизации:
- Специальные механизмы чтения и записи переменных
(std::atomic в C++11 и volatile в Java 5).
- Создание потоков и ожидание их завершения
- Различные другие библиотечные примитивы для синхронизации
• Модель памяти языка программирования определяет каким
образом исполнение операций синхронизации создает
отношение «произошло до»
- Без них, разные потоки выполняются параллельно
- Можно доказать те или иные свойства многопоточного кода,
используя гарантии на возможные исполнения, которые дает
модель памяти
Конфликты (data race)
• Если две операции над переменной произошли параллельно
(нет отношения произошло до) и одна из них это запись, то
такая ситуация называется конфликтом (так же известным
как гонка данных, data race).
- Это свойство конкретного исполнения
• Программа, в любом допустимом исполнении которой (с точки
зрения модели памяти) нет конфликтов, называется
корректно синхронизированный
- Модель памяти C++11 описывает поведение только корректно
синхронизированных программ
- Модель памяти Java 5 дает определенные (слабые и сложные
для понимания) гарантии и программам с конфликтами
Свойства исполнений над общими объектами
http://blog.lib.umn.edu/cspg/electionacademy/images/sharing.jpg
Операции над общими объектами
x.w(1)
объект
операция
аргумент
x.r:1
объект
операция
результат
Запись (write)
общей переменной
Чтение (read)
общей переменной
Последовательное исполнение
• Исполнение системы называется последовательным, если
все операции линейно-упорядочены отношением «произошло
до», то есть ∀𝑒, 𝑓 ∈ 𝐻: 𝑒 = 𝑓 ∨ 𝑒 → 𝑓 ∨ 𝑓 → 𝑒
P
Q
x.w(1)
x.r:1 последовательное
P
Q
x.w(1)
x.r:1 параллельное
Правильное исполнение
• 𝐻 𝑃 – сужение исполнения на поток 𝑃, то есть исполнение, где
остались только операции происходящие в потоке 𝑃
• Исполнение называется правильным (well-formed), если его
сужение на каждый поток 𝑃 является последовательным
историей
P
Q
x.w(1)
x.r: 1 правильное
P
Q
x.w(1)
x.r: 1 неправильное
x.r: 1
x.r: 1
Нас интересуют только правильные исполнения
Последовательная спецификация объекта
• 𝐻 𝑥 – сужение исполнения на объект 𝑥, то есть исполнение,
где остались только операции происходящие над объектом 𝑥
• Если сужение исполнения на объект является
последовательным, то можно проверить его на соответствие
последовательной спецификации объекта
- То, что мы привыкли видеть в обычном мире последовательного
программирования
- Например:
• Чтение переменной должно вернуть последнее записанное
значение.
• Операции deque на объекте FIFO очереди должны
возвращать значения в том порядке, в котором они
передавались в операцию enqueue.
Допустимое последовательное исполнение
• Последовательное исполнение является допустимым (legal),
если выполнены последовательные спецификации всех
объектов
P
Q
x.w(1)
x.r:1
Допустимое
P
Q
x.w(1)
x.r:0
Недопустимое
Условия согласованности (корректности)
• Как определить допустимость параллельного исполнения?
- Сопоставив ему эквивалентное (состоящее из тех же событий и
операций) допустимое последовательное исполнение
- Как именно – тут есть варианты: условия согласованности
• Аналог «корректности» в мире параллельного
программирования
• Условий согласованности много, из них основные
(удовлетворяющие базовому требованию) это:
- Последовательная согласованность
- Линеаризуемость
Базовое требование: корректные
последовательные программы должны
работать корректно в одном потоке
Последовательная согласованность (1)
• Исполнение последовательно согласовано, если можно
сопоставить эквивалентное ему допустимое
последовательное исполнение, которое сохраняет
программный порядок – порядок операций на каждом потоке
P
Q
x.w(1)
x.r:0 Последовательно
согласовано
P
Q
x.w(1)
x.r:2 НЕТ
R
x.r:1
S
x.r:0
x.r:1
Последовательная согласованность (2)
• Используется как условие корректности исполнения всей
системы в целом
- когда нет никакого «внешнего» наблюдателя, который может
«увидеть» фактический порядок между операциями на разных
процессах
• Модель памяти языка программирования и системы
исполнения кода использует последовательную
согласованность
- В том числе, С++11 и Java 5 (JMM = JLS Chapter 17)
Последовательная согласованность не говорит о том, когда
операция физически на самом деле была выполнена
Последовательная согласованность (3)
• Последовательная согласованность на каждом объекте по
отдельности не влечет последовательную согласованность
всего исполнения
P
Q
s.enc(1)
t.enq(2)
t.enc(1)
s.enq(2)
s.deq:2
t.deq:1
ПРИМЕР: (здесь 𝑠 и 𝑡 это две FIFO очереди)
Последовательную согласованность нельзя использовать для
спецификации поведения отдельных объектов в системе
Линеаризуемость
• Исполнение линеаризуемо если можно сопоставить
эквивалентное ему допустимое последовательное
исполнение, которое сохраняет порядок «произошло до»
P
x.w(1)
Последовательно
согласовано,
не линеаризуемо
P
Q
x.w(1)
x.r:0 линеаризуемо
Q
x.r:0
x.r:1
Свойства линеаризуемости
• В линеаризуемом исполнении каждой операции 𝑒 можно
сопоставить некое глобальное время (точку линеаризации)
𝑡 𝑒 ∈ ℝ так, что время разных операций различно и
𝑒 → 𝑓 ⇒ 𝑡 𝑒 < 𝑡(𝑓)
- Это эквивалентное определение линеаризуемости
• Линеаризуемость локальна. Линеаризуемость исполнения на
каждом объекте эквивалентна линеаризуемости исполнения
системы целиком
• Операции над линеаризуемыми объектами называют
атомарными.
- Они происходят как бы мгновенно и в определенном порядке, как
бы в каком-то глобальном времени
Линеаризуемость в глобальном времени
• В глобальном времени исполнение линеаризуемо тогда и
только тогда, когда точки линеаризации могут быть выбраны
так, что
P
Q
x.w(1)
x.r:1
R
x.r:0
линеаризуемо
∀𝑒: 𝑡𝑖𝑛𝑣 𝑒 < 𝑡 𝑒 < 𝑡 𝑟𝑒𝑠𝑝(𝑒)
Исполнение системы, выполняющей операции
над линеаризуемыми (атомарными) объектами,
можно анализировать в модели чередования
Линеаризуемость и чередование
Иерархия линеаризуемых объектов
• Из более простых линеаризуемых объектов можно делать
линеаризуемые объекты более высокого уровня
• Когда говорят что какой-то объект безопасен для
использования из нескольких потоков (thread-safe), то по
умолчанию имеют в виду линеаризуемость операций над ним
Доказав линеаризуемость сложного объекта, можно
абстрагироваться от деталей
реализации в нем, считать операции над ним
атомарными и строить объекты более высокого уровня
Применительно к Java
• Все операции над volatile полями в Java, согласно JMM,
являются операциями синхронизации (17.4.2), которые
всегда линейно-упорядочены в любом исполнении (17.4.4) и
согласованы с точки зрения чтения/записи (17.4.7)
- А значит являются линеаризуемыми
• Но операции над не volatile полями воистину могут нарушать
не только линеаризуемость, но и последовательную
согласованность (в отсутствии синхронизации)
P
Q
x.w(1)
x.r:1 допустимо в JMMx.r:0 x.r:1
Применительно к Java (2)
• Если программа корректно синхронизирована (в ней нет
гонок), то JMM дает гарантию последовательно
согласованного исполнения для всего кода
- Даже для кода работающего с не volatile переменными
- Если доступ к них синхронизирован (через операции
синхронизации) и гонок не возникает
• В С++11 есть примитивы для получения аналогичных гарантий
Построение линеаризуемых объектов
• Как построить линеаризуемый объект из последовательного?
- Если у нас есть атомарные (линеаризуемые) переменные
class Queue:
int head
int tail
E elems[N]
def enq(x):
elems[tail] = x
tail = (tail + 1) % N
def deq:
result = elems[head]
head = (head + 1) % N
return result
Не безопасно использовать из
разных потоков (not thread-safe)
Даже если написать на Java и всё
сделать volatile или на C++ всё
делать через std::atomic
Сложный объект составленный
из линеаризуемых не является
линеаризуемым «автоматом». Его
линеаризуемость надо доказать.
http://www.flickr.com/photos/xserve/368758286/
Взаимное исключение
• Защитим каждую операцию специальным объектом mutex
(mutual exclusion), также известного как блокировка (lock)
class Queue:
Mutex mutex
…
def enq(x):
mutex.lock
…
mutex.unlock
def deq:
mutex.lock
…
mutex.unlock
return result
Так чтобы реализация (тело) каждого
метода не выполнялось
одновременно, то есть все тела
методов выполнялись бы
последовательно.
Значит будет работать обычный
последовательный код
Взаимное исключение формально
• Главное свойство называется
взаимное исключение:
Критические секции не могут
выполняться параллельно:
• Это требование корректности
протокола взаимной блокировки
• Так же предъявляют различные
требования прогресса
thread Pid:
loop forever:
1: nonCriticalSection
2: mutex.lock
3: criticalSection
4: mutex.unlock
Протокол
ijji CSCSCSCSjiji  :,
Использование взаимного исключения
• Примитивы взаимного исключения доступны в стандартных
библиотеках
- std::mutex и std::lock в C++11
- synchronized и j.u.c.l.Lock в Java 5
• Любой последовательный объект можно сделать
параллельным, линеаризуемым
- Это т.н. грубая блокировка. Блокируем все операции над
данным объектом целиком
- Можно использовать тонкую блокировку
• Блокировать только операции над общими объектами внутри
метода, но не вызов метода целиком
• Но тогда, для обеспечения линеаризуемости, нужно
использовать двухфазную блокировку
Проблемы взаимного исключения
• Условные условия прогресса
- Есть гарантия прогресса (выполнение операций) в системе
только если критические секции выполняются за конечное время
• Инверсия приоритетов
- Возникает при блокировке потоков с разным приоритетом на
одном объекте
• Последовательное выполнение операций
- Нет параллелизма при выполнении критической секции, а значит
ограничена вертикальная масштабируемость
Закон Амдала для параллельной работы
• Максимальное убыстрение при запуске кода в N потоков если
доля S выполняется последовательно
• Даже при 5% последовательного кода (S=0.05), максимальное
убыстрение равно 20.
N
S
S
speedup



1
1
S
speedup
N
1
lim 

Проблемы взаимного исключения:
взаимная блокировка (deadlock)
thread P:
1: mutex1.lock
2: mutex2.lock
….
3: mutex2.unlock
4: mutex1.unlock
thread Q:
1: mutex2.lock
2: mutex1.lock
….
3: mutex1.unlock
4: mutex2.unlock
P Q
Цикл в графе ожидания приводит к
взаимной блокировке
Избежать появления такого цикла
можно с помощью иерархической
блокировки (глобально упорядочив все
блокировки)
Проблемы взаимного исключения:
потеря времени на переключение контекста
• Поток, который пытается
войти в занятую критическую
секцию, нужно усыпить
(переключить контекст)
• А потом разбудить
(переключить контекст),
когда критическая секция
освободится
• Переключение контекста –
это дорогая операция
(занимает много времени и
вытесняет данные из кэшей)
1. Enter Lock
2. Context Switch
3. Try to lock
4. Context Switch
5. Exit Lock
6. Context switch
and enter lock
Безусловные условия прогресса
• Отсутствие помех (obstruction-freedom)
- Если несколько потоков пытаются выполнить операцию, то любой
из них должен выполнить её за конечное время, если все другие
потоки остановить в любом месте (чтобы не мешали)
• Отсутствие блокировки (lock-freedom)
- Если несколько потоков пытаются выполнить операцию, то хотя
бы один из них должен выполнить её за конечное время (не
зависимо от действия или бездействия других потоков)
• Отсутствие ожидания (wait-freedom)
- Если какой-то поток пытается выполнить операцию, то он
выполнит её за конечное время (не зависимо от действия или
бездействия других потоков)
Объекты без блокировки
• Используя блокировку (lock) мы не можем получить объект
без блокировки (lock-free) и даже без помех (obstruction-free)
- Если поток пытаются выполнить операцию, когда какой-то другой
поток находится внутри критической секции и ничего не делает
(не получает время от операционной системы), то ничего не
получаетcя. Он ждет неограниченное время (освобождения
блокировки), независимо от того, сколько процессорного времени
ему будет выделено
• Не будем использовать блокировки. У нас есть переменные,
чтение и запись которые линеаризуемо без ожидания
Какие линеаризуемые объекты можно
построить без ожидания?
Атомарный снимок состояния N регистров
• Набор атомарных
переменный (по одной на
поток)
• Любой поток может
вызвать scan() чтобы
получить снимок состояния
всех переменных
• Методы должны быть
атомарными
(линеаризуемыми)
// Последовательная спецификация
class Snapshot:
shared int r[N]
def update(i, x):
r[i] = x
def scan():
return copy()
private def copy():
res = new int[N]
for i = 0..N-1: res[i] = r[i]
return res
Атомарный снимок состояния N регистров
• Наивная реализация не обеспечивает атомарность
R
W0
r[0].read:0
Пример
нелинеаризуемого
исполнения
r[1].read:3
update(0,2)
W1
update(1,3)
scan: [0, 3]
Операция r[0] r[1]
update(0,2) 2 0
update(1,3) 2 3
Атомарный снимок состояния N регистров,
без блокировок (lock free)
• Каждая переменная хранит
версию
• При обновлении значения,
увеличиваем версию на один
• При чтении, читаем до тех
пор, пока не получим два
подряд одинаковых снимка
shared (int x, int v) r[N]
// wait-free
def update(i, x):
r[i] = (x, r[i].v + 1)
// lock-free
def scan():
old = copy()
loop:
cur = copy()
if forall i: cur[i].v == old[i].v:
return cur.x
old = cur
Атомарный снимок состояния N регистров,
без ожидания (wait-free) – update
• Для реализации без
ожидания надо чтобы потоки
помогали друг другу
• Каждая переменная так же
хранит копию снимка s
• При обновлении делаем
вложенный scan, чтобы
помочь параллельно
работающим операциям
shared (int x, int v, int[N] s) r[N]
def update(i, x):
s = scan()
r[i] = (x, r[i].v + 1, s)
Атомарный снимок состояния N регистров,
без ожидания (wait-free) – scan
• Лемма: Если значение
поменялось второй раз, то
хранящаяся там копия
снимка s была получена
вложенной операцией scan
• Следствие: Этот алгоритм
выдает атомарный снимок
shared (int x, int v, int[N] s) r[N]
// wait-free, O(N^2)
def scan():
old = copy()
boolean updated[N]
loop:
cur = copy()
for i = 0..N-1:
if cur[i].v != old[i].v:
if updated[i]: return cur.s
else:
update[i] = true
old = cur
continue loop
return cur.x
Атомарный снимок состояния N регистров,
без ожидания (wait-free) – лемма
• Лемма: Если значение поменялось второй раз, то
хранящаяся там копия снимка s была получена вложенной
операцией scan.
W
R
scan write scan writescan write
scan
Можно ли построить более
сложные объекты
(очереди, например)
без ожидания?
Консенсус
Задача о консенсусе
• Согласованность
(consistent): все потоки
должны вернуть одно и то же
значение из метода decide
• Обоснованность (valid):
возвращенное значение было
входным значением какого-то
из потоков
class Consensus:
def decide(val):
…
return decision
Будем пытаться реализовать протокол консенсуса
используя регистры и другие примитивы
 Каждый поток использует
объект Consensus один раз
Консенсус с блокировкой
• Тривиальная реализация
протокола консенсуса с
помощью взаимного
исключения для любого
количества потоков
• Но мы хотим реализацию
без ожидания (wait-free)
shared int decision // init NA
Mutex mutex
def decide(val):
mutex.lock()
if decision == NA:
decision = val
mutex.unlock()
return decision
Консенсусное число
• Если с помощью класса [атомарных] объектов C и атомарных
регистров (переменных) можно реализовать консенсусный
протокол без ожидания (wait-free) для N потоков (и не
больше), то говорят что у класса C консенсусное число
равно N
• ТЕОРЕМА: Атомарные регистры (общие переменные с
операциями read/write) имеют консенсусное число 1
- Т.е. с помощью атомарных переменных даже 2 потока не могут
придти к консенсусу без ожидания
- М. Херлихи, 1991 год
Read-Modify-Write регистры
• Для функции или класса
функций F(args)
- getAndSet (exchange),
getAndIncrement, getAndAdd и
т.п.
- get (read) это тоже
[тривиальная] RMW операция
без дополнительных
аргументов для F() == id
class RMWRegister:
private shared int reg
def read():
return reg
def getAndF(args):
do atomically:
old = reg
reg = F(args)(reg)
return old
Нетривиальные RMW регистры
• Консенсусное число
нетривиального RMW
регистра >= 2
- Нужно чтобы была хотя бы
одна «подвижная» точка
функции F, например
F(v0) == v1 != v0
threadlocal int id // 0 or 1
shared RMWRegister rmw
shared int proposed[2]
def decide(val):
proposed[id] = val
if rmw.getAndF() == v0:
return proposed[i]
else:
return proposed[1-i]
Реализация протокола
для 2-х потоков
Common2 RMW регистры
• Определения
- F1 и F2 коммутируют если F1(F2(x)) == F2(F1(x))
- F1 перезаписывает F2 если F1(F2(x)) == F1(x)
- Класс С RMW регистров принадлежит Common2, если любая
пара функций либо коммутирует, либо одна из функций
перезаписывает другую
• ТЕОРЕМА: Нетривиальный класс Common2 RMW регистров
имеет консенсусное число 2
- Три потока уже не могут решить задачу консенсуса
Универсальные объекты
• Объект с консенсусный
числом бесконечность
называется
«универсальный объект».
- По определению, с
помощью него можно
реализовать консенсусный
протокол для любого числа
потоков
class CASRegister:
private shared int reg
def CAS(expect, update):
do atomically:
old = reg
if old == expect:
reg = update
return true
return false
Примеры:
 compareAndSet (СAS) aka testAndSet (возвращает boolean)
 compareAndExchange aka CMPXCHG (возвращает старое
значение как и положено RMW операции)
CAS и консенсус
def decide(val):
if CAS(NA, val):
return val
else:
return read()
Реализация протокола
через CAS+READ
def decide(val):
old = CMPXCHG(NA, val):
if old == NA:
return val
else:
return old
Реализация протокола
через CMPXCHG
Универсальность консенсуса
• ТЕОРЕМА: Любой последовательный объект можно
реализовать без ожидания (wait-free) для N потоков используя
консенсусный протокол для N объектов
- Такое построение называется универсальная конструкция
- Следствие 1: С помощью любого класса объектов с
консенсусным числом N можно реализовать любой объект с
консенсусным числом <= N.
- Следствие 2: С помощью универсального объекта можно
реализовать вообще любой объект
• Cначала реализуем консенсус для любого числа потоков (по
определению универсального объекта)
• Потом через консенсус любой другой объект используя
универсальную конструкцию
Иерархия объектов
Объект Консенсусное
число
Атомарные регистры, снимок состояния нескольких
регистров
1
getAndSet (атомарный обмен), getAndAdd, очередь
(только enqueue/dequeue), стек (только push/pop)
2
Атомарная запись m регистров из m(m+1)/2 регистров m
compareAndSet, LoadLinked/StoreConditional, очередь с
операций peek, многие другие сложные структуры данных
∞
Универсальные операции (на
практике это обычно CAS)
необходимы для реализации
любых нетривиальных структур
данных без блокировки
Рекомендованная литература
В своем блоге elizarov.livejournal.com я размещу ссылки
на научные работы для дополнительного чтения по теме
Спасибо за внимание
Слайды также будут выложены на elizarov.livejournal.com

Contenu connexe

Tendances

Lecture1: Introduction to Parallel Computing
Lecture1: Introduction to  Parallel ComputingLecture1: Introduction to  Parallel Computing
Lecture1: Introduction to Parallel ComputingAndrii Rodionov
 
Параллельные алгоритмы обработки данных
Параллельные алгоритмы обработки данныхПараллельные алгоритмы обработки данных
Параллельные алгоритмы обработки данныхSergey Vasilyev
 
сортировка слияниями
сортировка слияниямисортировка слияниями
сортировка слияниямиDmitry Protopopov
 
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla Systems Inc.
 
Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...
Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...
Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...Positive Hack Days
 
Алгоритмы и структуры данных осень 2013 лекция 3
Алгоритмы и структуры данных осень 2013 лекция 3Алгоритмы и структуры данных осень 2013 лекция 3
Алгоритмы и структуры данных осень 2013 лекция 3Technopark
 
FreeRTOS
FreeRTOSFreeRTOS
FreeRTOSquakke
 
Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...
Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...
Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...Mikhail Kurnosov
 
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияAlexey Paznikov
 
Высокоуровневая обработка событий
Высокоуровневая обработка событий Высокоуровневая обработка событий
Высокоуровневая обработка событий Bonart
 
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...Ontico
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...Alexey Paznikov
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Stfalcon Meetups
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Alexey Paznikov
 
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Mikhail Kurnosov
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2Eugeniy Tyumentcev
 
PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...
PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...
PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...pgdayrussia
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Mikhail Kurnosov
 
Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Mikhail Kurnosov
 

Tendances (20)

Lecture1: Introduction to Parallel Computing
Lecture1: Introduction to  Parallel ComputingLecture1: Introduction to  Parallel Computing
Lecture1: Introduction to Parallel Computing
 
Параллельные алгоритмы обработки данных
Параллельные алгоритмы обработки данныхПараллельные алгоритмы обработки данных
Параллельные алгоритмы обработки данных
 
сортировка слияниями
сортировка слияниямисортировка слияниями
сортировка слияниями
 
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak OleksiiSvitla .Net meetup in Kiev, Anzhiiak Oleksii
Svitla .Net meetup in Kiev, Anzhiiak Oleksii
 
Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...
Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...
Алгоритмы решения задачи о булевой выполнимости (SAT) и их применение в крипт...
 
Алгоритмы и структуры данных осень 2013 лекция 3
Алгоритмы и структуры данных осень 2013 лекция 3Алгоритмы и структуры данных осень 2013 лекция 3
Алгоритмы и структуры данных осень 2013 лекция 3
 
FreeRTOS
FreeRTOSFreeRTOS
FreeRTOS
 
Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...
Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...
Лекция 12. Вероятностный анализ и рандомизированные алгоритмы (Randomized al...
 
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
 
Высокоуровневая обработка событий
Высокоуровневая обработка событий Высокоуровневая обработка событий
Высокоуровневая обработка событий
 
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...
Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный...
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
Discovering Lambdas in Java 8
Discovering Lambdas in Java 8Discovering Lambdas in Java 8
Discovering Lambdas in Java 8
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2
 
Discovering Lambdas (Speech)
Discovering Lambdas (Speech)Discovering Lambdas (Speech)
Discovering Lambdas (Speech)
 
PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...
PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...
PG Day'14 Russia, PostgreSQL как платформа для разработки приложений, часть 3...
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
 
Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)
 

En vedette

ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
Why GC is eating all my CPU?
Why GC is eating all my CPU?Why GC is eating all my CPU?
Why GC is eating all my CPU?Roman Elizarov
 
Wait for your fortune without Blocking!
Wait for your fortune without Blocking!Wait for your fortune without Blocking!
Wait for your fortune without Blocking!Roman Elizarov
 
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
Пишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данныхПишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данныхRoman Elizarov
 
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
The theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmerThe theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmerRoman Elizarov
 
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
20140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture0920140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture09Computer Science Club
 
Михаил Елизаров «Man in the middle в действии!»
Михаил Елизаров «Man in the middle в действии!»Михаил Елизаров «Man in the middle в действии!»
Михаил Елизаров «Man in the middle в действии!»Mail.ru Group
 
Our Projects
Our ProjectsOur Projects
Our ProjectsHangar
 

En vedette (13)

ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
 
Why GC is eating all my CPU?
Why GC is eating all my CPU?Why GC is eating all my CPU?
Why GC is eating all my CPU?
 
Wait for your fortune without Blocking!
Wait for your fortune without Blocking!Wait for your fortune without Blocking!
Wait for your fortune without Blocking!
 
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
 
Пишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данныхПишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данных
 
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
 
The theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmerThe theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmer
 
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
 
20140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture0920140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture09
 
24 Multithreaded Algorithms
24 Multithreaded Algorithms24 Multithreaded Algorithms
24 Multithreaded Algorithms
 
Михаил Елизаров «Man in the middle в действии!»
Михаил Елизаров «Man in the middle в действии!»Михаил Елизаров «Man in the middle в действии!»
Михаил Елизаров «Man in the middle в действии!»
 
Our Projects
Our ProjectsOur Projects
Our Projects
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 

Similaire à Многопоточные Алгоритмы (для BitByte 2014)

Atomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAtomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAlexey Fyodorov
 
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 FyodorovJavaDayUA
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Mikhail Kurnosov
 
Алгоритмы и структуры данных осень 2013 лекция 1
Алгоритмы и структуры данных осень 2013 лекция 1Алгоритмы и структуры данных осень 2013 лекция 1
Алгоритмы и структуры данных осень 2013 лекция 1Technopark
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILRoman Brovko
 
модель акторов и C++ что, зачем и как ?
модель акторов и C++ что, зачем и как ?модель акторов и C++ что, зачем и как ?
модель акторов и C++ что, зачем и как ?corehard_by
 
Анализ количества посетителей на сайте [Считаем уникальные элементы]
Анализ количества посетителей на сайте [Считаем уникальные элементы]Анализ количества посетителей на сайте [Считаем уникальные элементы]
Анализ количества посетителей на сайте [Считаем уникальные элементы]Qrator Labs
 
Иван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеИван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеYandex
 
Checkpoint and Restore In Userspace: Готово или нет?
Checkpoint and Restore In Userspace: Готово или нет?Checkpoint and Restore In Userspace: Готово или нет?
Checkpoint and Restore In Userspace: Готово или нет?OpenVZ
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.Unguryan Vitaliy
 
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Mikhail Kurnosov
 
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?Yauheni Akhotnikau
 
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?Yandex
 
якобовский - введение в параллельное программирование (1)
якобовский - введение в параллельное программирование (1)якобовский - введение в параллельное программирование (1)
якобовский - введение в параллельное программирование (1)Michael Karpov
 

Similaire à Многопоточные Алгоритмы (для BitByte 2014) (20)

Atomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAtomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithms
 
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
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
 
Алгоритмы и структуры данных осень 2013 лекция 1
Алгоритмы и структуры данных осень 2013 лекция 1Алгоритмы и структуры данных осень 2013 лекция 1
Алгоритмы и структуры данных осень 2013 лекция 1
 
2020 03-31-lection
2020 03-31-lection2020 03-31-lection
2020 03-31-lection
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GIL
 
модель акторов и C++ что, зачем и как ?
модель акторов и C++ что, зачем и как ?модель акторов и C++ что, зачем и как ?
модель акторов и C++ что, зачем и как ?
 
Rx
RxRx
Rx
 
Анализ количества посетителей на сайте [Считаем уникальные элементы]
Анализ количества посетителей на сайте [Считаем уникальные элементы]Анализ количества посетителей на сайте [Считаем уникальные элементы]
Анализ количества посетителей на сайте [Считаем уникальные элементы]
 
Иван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программированиеИван Пузыревский — Введение в асинхронное программирование
Иван Пузыревский — Введение в асинхронное программирование
 
Checkpoint and Restore In Userspace: Готово или нет?
Checkpoint and Restore In Userspace: Готово или нет?Checkpoint and Restore In Userspace: Готово или нет?
Checkpoint and Restore In Userspace: Готово или нет?
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.
 
Threads in java
Threads in javaThreads in java
Threads in java
 
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
 
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
 
Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?
 
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
 
Lab5
Lab5Lab5
Lab5
 
лекция 2
лекция 2лекция 2
лекция 2
 
якобовский - введение в параллельное программирование (1)
якобовский - введение в параллельное программирование (1)якобовский - введение в параллельное программирование (1)
якобовский - введение в параллельное программирование (1)
 

Plus de Roman Elizarov

Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Roman Elizarov
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Roman Elizarov
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Roman Elizarov
 
Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Roman Elizarov
 
Scale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOneScale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOneRoman Elizarov
 
Kotlin Coroutines Reloaded
Kotlin Coroutines ReloadedKotlin Coroutines Reloaded
Kotlin Coroutines ReloadedRoman Elizarov
 
Lock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesLock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesRoman Elizarov
 
Introduction to Kotlin coroutines
Introduction to Kotlin coroutinesIntroduction to Kotlin coroutines
Introduction to Kotlin coroutinesRoman Elizarov
 
Non blocking programming and waiting
Non blocking programming and waitingNon blocking programming and waiting
Non blocking programming and waitingRoman Elizarov
 
Java Serialization Facts and Fallacies
Java Serialization Facts and FallaciesJava Serialization Facts and Fallacies
Java Serialization Facts and FallaciesRoman Elizarov
 
Millions quotes per second in pure java
Millions quotes per second in pure javaMillions quotes per second in pure java
Millions quotes per second in pure javaRoman Elizarov
 
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 

Plus de Roman Elizarov (13)

Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017
 
Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017
 
Scale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOneScale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOne
 
Kotlin Coroutines Reloaded
Kotlin Coroutines ReloadedKotlin Coroutines Reloaded
Kotlin Coroutines Reloaded
 
Lock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesLock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin Coroutines
 
Introduction to Kotlin coroutines
Introduction to Kotlin coroutinesIntroduction to Kotlin coroutines
Introduction to Kotlin coroutines
 
Non blocking programming and waiting
Non blocking programming and waitingNon blocking programming and waiting
Non blocking programming and waiting
 
DIY Java Profiling
DIY Java ProfilingDIY Java Profiling
DIY Java Profiling
 
Java Serialization Facts and Fallacies
Java Serialization Facts and FallaciesJava Serialization Facts and Fallacies
Java Serialization Facts and Fallacies
 
Millions quotes per second in pure java
Millions quotes per second in pure javaMillions quotes per second in pure java
Millions quotes per second in pure java
 
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
 

Многопоточные Алгоритмы (для BitByte 2014)

  • 2. Закон Мура и “The free lunch is over” http://www.gotw.ca/publications/concurrency-ddj.htm Зеленая линия = Тысяч транзисторов aka “Закон Мура” Под ней = Частота (MHz)
  • 3. Нужна формальная модель параллельных вычислений • Чтобы доказывать: - корректность алгоритмов - невозможность построения тех или иных алгоритмов - минимально-необходимые требования для тех или иных алгоритмов • Для формализации отношений между прикладным программистом и разработчиком компилятора и системы исполнения кода
  • 4. Модель с общими объектами (общей памятью) Поток1 Поток2 ПотокN Общая память Объект M Объект 2 Объект 1
  • 5. Общие объекты • Потоки выполняют операции над общими, разделяемыми объектами • В этой модели не важны операции внутри потоков: - Вычисления - Обновления регистров процессора - Обновления стека потока - Обновления любой другой локальной для потока памяти • Важна только коммуникация между потоками • В этой модели единственный тип коммуникации между потоками – это работа с общими объектами
  • 6. Общие переменные • Общие переменные – это просто простейший тип общего объекта: - У него есть значение определенного типа - Есть операция чтения (read) и записи (write). • Общие переменные – это базовые строительные блоки для параллельных алгоритмов • Модель с общими переменными – это хорошая абстракция современных многопроцессорных систем и многопоточных ОС - На практике, это область памяти процесса, которая одновременно доступна для чтения и записи всем потокам, исполняемым в данном процессе В теоретических трудах общие переменные называют регистрами
  • 7. Свойства параллельных программ • Последовательные программы детерминированы - Если нет явного использования случайных чисел и другого общения с недетерминированным внешним миром - Их свойства можно установить, анализируя последовательное исполнение при данных входных параметрах • Параллельные программы в общем случае недетерминированы - Даже если код каждого потока детерминирован - Результат работы зависит от фактического исполнения при данных входных параметрах • А этих исполнений может быть много - Говорим «программа А имеет свойство 𝑃», если программа A имеет свойство 𝑃 при любом допустимом исполнении
  • 8. Как моделировать параллельное выполнение? • Очень простая программа. Всего два потока (P и Q), каждый из которых последовательно выполняет 2 действия и останавливается (3-м действием). - У них есть общая переменная x - Какие есть варианты вывода на экран? thread P: 0: x = 1 1: print x 2: stop thread Q: 0: x = 2 1: print x 2: stop shared int x
  • 9. Моделирование исполнений через чередование операций • 𝑆 это общее состояние: - Состояние всех потоков - И состояние всех общих объектов • 𝑓 и 𝑔 это операции над объектами - Для переменных это операции чтения (вместе с результатом) и записи (вместе с значением) - Количество активных операций равно количеству потоков • 𝑓(𝑆) это новое состояние после применения операции 𝑓 в состоянии 𝑆 𝑔(𝑆)𝑓(𝑆) 𝑆 𝑓 𝑔
  • 10. Пример thread P: 0: x = 1 1: print x 2: stop thread Q: 0: x = 2 1: print x 2: stop P0,Q0 x=0 (-, -) P1,Q0 x=1 (-, -) P0,Q1 x=2 (-, -) P2,Q0 x=1 (1, -) P1,Q1 x=2 (-, -) P1,Q1 x=1 (-, -) P0,Q2 x=2 (-, 2) P2,Q2 x=2 (1, 2) P2,Q2 x=2 (2, 2) +1 state not shown +2 states not shown P2,Q2 x=1 (1, 1) +2 states not shown P2,Q2 x=1 (2, 1) +1 state not shown Всего 17 состояний shared int x
  • 11. Обсуждение модели • Эта модель не «параллельна» - Все операции происходят последовательно (только порядок заранее не задан) • А на самом деле на реальных процессорах операции чтения и записи памяти не мгновенные и происходит параллельно как в разных ядрах так и внутри одного ядра - В реальности процессор обменивается с памятью сообщениями чтения/записи и таких сообщений находящихся в обработке одновременно может быть очень много (!) Модель чередования не отражает фактическую реальность. Можно ли её использовать для анализа алгоритмов на практике? Когда её можно использовать?
  • 12. Физическая реальность (1) • Свет (электромагнитные волны) в вакууме распространяется со скоростью ~ 3 ∙ 108 м/c - Это максимальный физический предел скорости распространения света. В реальных материалах – медленней. • За один такт процессора с частотой 3 ГГц (3 ∙ 109 Гц) свет в вакууме проходит всего 10 см. - Соседние процессоры на плате физически не могут синхронизировать свою работу и физически не могут определить порядок происходящих в них событиях. - Они работают действительно параллельно.
  • 13. Физическая реальность (2) • Пусть 𝑎, 𝑏, 𝑐 ∈ 𝐸 – это физически атомарные (неделимые) события, происходящие в пространстве-времени - Говорим «𝑎 предшествует 𝑏» или «𝑎 произошло до 𝑏» (и записываем 𝑎 → 𝑏), если свет от точки пространства-времени 𝑎 успевает дойти до точки пространства-времени 𝑏 - Это отношение частичного порядка на событиях x t a b Световой конус Между 𝑎 и 𝑏 нет предшествования. Они происходят параллельно с 𝑎 → 𝑐 и 𝑏 → 𝑐
  • 14. Модель «произошло до» • Впервые введена Л. Лампортом в 1978 году • Исполнение системы – это пара (𝐻, → 𝐻) - 𝐻 – это множество операций 𝑒, 𝑓, 𝑔, … (чтение и запись ячеек памяти), произошедших во время исполнения - «→ 𝐻» – это транзитивное, антирефлексивное, асимметричное отношение (частичный строгий порядок) на множестве операций - 𝑒 → 𝐻 𝑓 означает что “𝑒 произошло до 𝑓 в исполнении 𝐻” • Чаще всего исполнение 𝐻 понятно из контекста и опускается • Две операции 𝑒 и 𝑓 параллельны (𝑒 ∥ 𝑓) если 𝑒 ↛ 𝑓 ⋀ 𝑓 ↛ 𝑒 • Система – это набор всех возможных исполнений системы - Говорим, что «система имеет свойство 𝑃», если каждое исполнение системы имеет свойство 𝑃
  • 15. Модель глобального времени • В этой модели каждая операция – это временной интервал 𝑒 = 𝑡𝑖𝑛𝑣 𝑒 , 𝑡 𝑟𝑒𝑠𝑝 𝑒 где t 𝑖𝑛𝑣 𝑒 , 𝑡 𝑟𝑒𝑠𝑝(𝑒) ∈ ℝ и 𝑡 P Q R 𝑒 𝑓 𝑔 Будем использовать эту модель во всех иллюстрациях Здесь: 𝑒 → f 𝑒 ∥ 𝑔 𝑓 ∥ 𝑔 𝑒 → 𝑓 ≝ 𝑡 𝑟𝑒𝑠𝑝 𝑒 < 𝑡𝑖𝑛𝑣(𝑓)
  • 16. Обсуждение глобального времени • Это всего лишь механизм, позволяющий визуализировать факт существования параллельных операций • При доказательстве различных фактов и анализе свойств [исполнений] системы время не используется - Анализируются только операции и отношения «произошло до» На самом деле, никакого глобального времени нет и не может быть из-за физических ограничений
  • 17. «произошло до» на практике • Современные языки программирования предоставляют программисту операции синхронизации: - Специальные механизмы чтения и записи переменных (std::atomic в C++11 и volatile в Java 5). - Создание потоков и ожидание их завершения - Различные другие библиотечные примитивы для синхронизации • Модель памяти языка программирования определяет каким образом исполнение операций синхронизации создает отношение «произошло до» - Без них, разные потоки выполняются параллельно - Можно доказать те или иные свойства многопоточного кода, используя гарантии на возможные исполнения, которые дает модель памяти
  • 18. Конфликты (data race) • Если две операции над переменной произошли параллельно (нет отношения произошло до) и одна из них это запись, то такая ситуация называется конфликтом (так же известным как гонка данных, data race). - Это свойство конкретного исполнения • Программа, в любом допустимом исполнении которой (с точки зрения модели памяти) нет конфликтов, называется корректно синхронизированный - Модель памяти C++11 описывает поведение только корректно синхронизированных программ - Модель памяти Java 5 дает определенные (слабые и сложные для понимания) гарантии и программам с конфликтами
  • 19. Свойства исполнений над общими объектами http://blog.lib.umn.edu/cspg/electionacademy/images/sharing.jpg
  • 20. Операции над общими объектами x.w(1) объект операция аргумент x.r:1 объект операция результат Запись (write) общей переменной Чтение (read) общей переменной
  • 21. Последовательное исполнение • Исполнение системы называется последовательным, если все операции линейно-упорядочены отношением «произошло до», то есть ∀𝑒, 𝑓 ∈ 𝐻: 𝑒 = 𝑓 ∨ 𝑒 → 𝑓 ∨ 𝑓 → 𝑒 P Q x.w(1) x.r:1 последовательное P Q x.w(1) x.r:1 параллельное
  • 22. Правильное исполнение • 𝐻 𝑃 – сужение исполнения на поток 𝑃, то есть исполнение, где остались только операции происходящие в потоке 𝑃 • Исполнение называется правильным (well-formed), если его сужение на каждый поток 𝑃 является последовательным историей P Q x.w(1) x.r: 1 правильное P Q x.w(1) x.r: 1 неправильное x.r: 1 x.r: 1 Нас интересуют только правильные исполнения
  • 23. Последовательная спецификация объекта • 𝐻 𝑥 – сужение исполнения на объект 𝑥, то есть исполнение, где остались только операции происходящие над объектом 𝑥 • Если сужение исполнения на объект является последовательным, то можно проверить его на соответствие последовательной спецификации объекта - То, что мы привыкли видеть в обычном мире последовательного программирования - Например: • Чтение переменной должно вернуть последнее записанное значение. • Операции deque на объекте FIFO очереди должны возвращать значения в том порядке, в котором они передавались в операцию enqueue.
  • 24. Допустимое последовательное исполнение • Последовательное исполнение является допустимым (legal), если выполнены последовательные спецификации всех объектов P Q x.w(1) x.r:1 Допустимое P Q x.w(1) x.r:0 Недопустимое
  • 25. Условия согласованности (корректности) • Как определить допустимость параллельного исполнения? - Сопоставив ему эквивалентное (состоящее из тех же событий и операций) допустимое последовательное исполнение - Как именно – тут есть варианты: условия согласованности • Аналог «корректности» в мире параллельного программирования • Условий согласованности много, из них основные (удовлетворяющие базовому требованию) это: - Последовательная согласованность - Линеаризуемость Базовое требование: корректные последовательные программы должны работать корректно в одном потоке
  • 26. Последовательная согласованность (1) • Исполнение последовательно согласовано, если можно сопоставить эквивалентное ему допустимое последовательное исполнение, которое сохраняет программный порядок – порядок операций на каждом потоке P Q x.w(1) x.r:0 Последовательно согласовано P Q x.w(1) x.r:2 НЕТ R x.r:1 S x.r:0 x.r:1
  • 27. Последовательная согласованность (2) • Используется как условие корректности исполнения всей системы в целом - когда нет никакого «внешнего» наблюдателя, который может «увидеть» фактический порядок между операциями на разных процессах • Модель памяти языка программирования и системы исполнения кода использует последовательную согласованность - В том числе, С++11 и Java 5 (JMM = JLS Chapter 17) Последовательная согласованность не говорит о том, когда операция физически на самом деле была выполнена
  • 28. Последовательная согласованность (3) • Последовательная согласованность на каждом объекте по отдельности не влечет последовательную согласованность всего исполнения P Q s.enc(1) t.enq(2) t.enc(1) s.enq(2) s.deq:2 t.deq:1 ПРИМЕР: (здесь 𝑠 и 𝑡 это две FIFO очереди) Последовательную согласованность нельзя использовать для спецификации поведения отдельных объектов в системе
  • 29. Линеаризуемость • Исполнение линеаризуемо если можно сопоставить эквивалентное ему допустимое последовательное исполнение, которое сохраняет порядок «произошло до» P x.w(1) Последовательно согласовано, не линеаризуемо P Q x.w(1) x.r:0 линеаризуемо Q x.r:0 x.r:1
  • 30. Свойства линеаризуемости • В линеаризуемом исполнении каждой операции 𝑒 можно сопоставить некое глобальное время (точку линеаризации) 𝑡 𝑒 ∈ ℝ так, что время разных операций различно и 𝑒 → 𝑓 ⇒ 𝑡 𝑒 < 𝑡(𝑓) - Это эквивалентное определение линеаризуемости • Линеаризуемость локальна. Линеаризуемость исполнения на каждом объекте эквивалентна линеаризуемости исполнения системы целиком • Операции над линеаризуемыми объектами называют атомарными. - Они происходят как бы мгновенно и в определенном порядке, как бы в каком-то глобальном времени
  • 31. Линеаризуемость в глобальном времени • В глобальном времени исполнение линеаризуемо тогда и только тогда, когда точки линеаризации могут быть выбраны так, что P Q x.w(1) x.r:1 R x.r:0 линеаризуемо ∀𝑒: 𝑡𝑖𝑛𝑣 𝑒 < 𝑡 𝑒 < 𝑡 𝑟𝑒𝑠𝑝(𝑒)
  • 32. Исполнение системы, выполняющей операции над линеаризуемыми (атомарными) объектами, можно анализировать в модели чередования Линеаризуемость и чередование
  • 33. Иерархия линеаризуемых объектов • Из более простых линеаризуемых объектов можно делать линеаризуемые объекты более высокого уровня • Когда говорят что какой-то объект безопасен для использования из нескольких потоков (thread-safe), то по умолчанию имеют в виду линеаризуемость операций над ним Доказав линеаризуемость сложного объекта, можно абстрагироваться от деталей реализации в нем, считать операции над ним атомарными и строить объекты более высокого уровня
  • 34. Применительно к Java • Все операции над volatile полями в Java, согласно JMM, являются операциями синхронизации (17.4.2), которые всегда линейно-упорядочены в любом исполнении (17.4.4) и согласованы с точки зрения чтения/записи (17.4.7) - А значит являются линеаризуемыми • Но операции над не volatile полями воистину могут нарушать не только линеаризуемость, но и последовательную согласованность (в отсутствии синхронизации) P Q x.w(1) x.r:1 допустимо в JMMx.r:0 x.r:1
  • 35. Применительно к Java (2) • Если программа корректно синхронизирована (в ней нет гонок), то JMM дает гарантию последовательно согласованного исполнения для всего кода - Даже для кода работающего с не volatile переменными - Если доступ к них синхронизирован (через операции синхронизации) и гонок не возникает • В С++11 есть примитивы для получения аналогичных гарантий
  • 36. Построение линеаризуемых объектов • Как построить линеаризуемый объект из последовательного? - Если у нас есть атомарные (линеаризуемые) переменные class Queue: int head int tail E elems[N] def enq(x): elems[tail] = x tail = (tail + 1) % N def deq: result = elems[head] head = (head + 1) % N return result Не безопасно использовать из разных потоков (not thread-safe) Даже если написать на Java и всё сделать volatile или на C++ всё делать через std::atomic Сложный объект составленный из линеаризуемых не является линеаризуемым «автоматом». Его линеаризуемость надо доказать.
  • 38. Взаимное исключение • Защитим каждую операцию специальным объектом mutex (mutual exclusion), также известного как блокировка (lock) class Queue: Mutex mutex … def enq(x): mutex.lock … mutex.unlock def deq: mutex.lock … mutex.unlock return result Так чтобы реализация (тело) каждого метода не выполнялось одновременно, то есть все тела методов выполнялись бы последовательно. Значит будет работать обычный последовательный код
  • 39. Взаимное исключение формально • Главное свойство называется взаимное исключение: Критические секции не могут выполняться параллельно: • Это требование корректности протокола взаимной блокировки • Так же предъявляют различные требования прогресса thread Pid: loop forever: 1: nonCriticalSection 2: mutex.lock 3: criticalSection 4: mutex.unlock Протокол ijji CSCSCSCSjiji  :,
  • 40. Использование взаимного исключения • Примитивы взаимного исключения доступны в стандартных библиотеках - std::mutex и std::lock в C++11 - synchronized и j.u.c.l.Lock в Java 5 • Любой последовательный объект можно сделать параллельным, линеаризуемым - Это т.н. грубая блокировка. Блокируем все операции над данным объектом целиком - Можно использовать тонкую блокировку • Блокировать только операции над общими объектами внутри метода, но не вызов метода целиком • Но тогда, для обеспечения линеаризуемости, нужно использовать двухфазную блокировку
  • 41. Проблемы взаимного исключения • Условные условия прогресса - Есть гарантия прогресса (выполнение операций) в системе только если критические секции выполняются за конечное время • Инверсия приоритетов - Возникает при блокировке потоков с разным приоритетом на одном объекте • Последовательное выполнение операций - Нет параллелизма при выполнении критической секции, а значит ограничена вертикальная масштабируемость
  • 42. Закон Амдала для параллельной работы • Максимальное убыстрение при запуске кода в N потоков если доля S выполняется последовательно • Даже при 5% последовательного кода (S=0.05), максимальное убыстрение равно 20. N S S speedup    1 1 S speedup N 1 lim  
  • 43. Проблемы взаимного исключения: взаимная блокировка (deadlock) thread P: 1: mutex1.lock 2: mutex2.lock …. 3: mutex2.unlock 4: mutex1.unlock thread Q: 1: mutex2.lock 2: mutex1.lock …. 3: mutex1.unlock 4: mutex2.unlock P Q Цикл в графе ожидания приводит к взаимной блокировке Избежать появления такого цикла можно с помощью иерархической блокировки (глобально упорядочив все блокировки)
  • 44. Проблемы взаимного исключения: потеря времени на переключение контекста • Поток, который пытается войти в занятую критическую секцию, нужно усыпить (переключить контекст) • А потом разбудить (переключить контекст), когда критическая секция освободится • Переключение контекста – это дорогая операция (занимает много времени и вытесняет данные из кэшей) 1. Enter Lock 2. Context Switch 3. Try to lock 4. Context Switch 5. Exit Lock 6. Context switch and enter lock
  • 45.
  • 46. Безусловные условия прогресса • Отсутствие помех (obstruction-freedom) - Если несколько потоков пытаются выполнить операцию, то любой из них должен выполнить её за конечное время, если все другие потоки остановить в любом месте (чтобы не мешали) • Отсутствие блокировки (lock-freedom) - Если несколько потоков пытаются выполнить операцию, то хотя бы один из них должен выполнить её за конечное время (не зависимо от действия или бездействия других потоков) • Отсутствие ожидания (wait-freedom) - Если какой-то поток пытается выполнить операцию, то он выполнит её за конечное время (не зависимо от действия или бездействия других потоков)
  • 47. Объекты без блокировки • Используя блокировку (lock) мы не можем получить объект без блокировки (lock-free) и даже без помех (obstruction-free) - Если поток пытаются выполнить операцию, когда какой-то другой поток находится внутри критической секции и ничего не делает (не получает время от операционной системы), то ничего не получаетcя. Он ждет неограниченное время (освобождения блокировки), независимо от того, сколько процессорного времени ему будет выделено • Не будем использовать блокировки. У нас есть переменные, чтение и запись которые линеаризуемо без ожидания Какие линеаризуемые объекты можно построить без ожидания?
  • 48. Атомарный снимок состояния N регистров • Набор атомарных переменный (по одной на поток) • Любой поток может вызвать scan() чтобы получить снимок состояния всех переменных • Методы должны быть атомарными (линеаризуемыми) // Последовательная спецификация class Snapshot: shared int r[N] def update(i, x): r[i] = x def scan(): return copy() private def copy(): res = new int[N] for i = 0..N-1: res[i] = r[i] return res
  • 49. Атомарный снимок состояния N регистров • Наивная реализация не обеспечивает атомарность R W0 r[0].read:0 Пример нелинеаризуемого исполнения r[1].read:3 update(0,2) W1 update(1,3) scan: [0, 3] Операция r[0] r[1] update(0,2) 2 0 update(1,3) 2 3
  • 50. Атомарный снимок состояния N регистров, без блокировок (lock free) • Каждая переменная хранит версию • При обновлении значения, увеличиваем версию на один • При чтении, читаем до тех пор, пока не получим два подряд одинаковых снимка shared (int x, int v) r[N] // wait-free def update(i, x): r[i] = (x, r[i].v + 1) // lock-free def scan(): old = copy() loop: cur = copy() if forall i: cur[i].v == old[i].v: return cur.x old = cur
  • 51. Атомарный снимок состояния N регистров, без ожидания (wait-free) – update • Для реализации без ожидания надо чтобы потоки помогали друг другу • Каждая переменная так же хранит копию снимка s • При обновлении делаем вложенный scan, чтобы помочь параллельно работающим операциям shared (int x, int v, int[N] s) r[N] def update(i, x): s = scan() r[i] = (x, r[i].v + 1, s)
  • 52. Атомарный снимок состояния N регистров, без ожидания (wait-free) – scan • Лемма: Если значение поменялось второй раз, то хранящаяся там копия снимка s была получена вложенной операцией scan • Следствие: Этот алгоритм выдает атомарный снимок shared (int x, int v, int[N] s) r[N] // wait-free, O(N^2) def scan(): old = copy() boolean updated[N] loop: cur = copy() for i = 0..N-1: if cur[i].v != old[i].v: if updated[i]: return cur.s else: update[i] = true old = cur continue loop return cur.x
  • 53. Атомарный снимок состояния N регистров, без ожидания (wait-free) – лемма • Лемма: Если значение поменялось второй раз, то хранящаяся там копия снимка s была получена вложенной операцией scan. W R scan write scan writescan write scan
  • 54. Можно ли построить более сложные объекты (очереди, например) без ожидания?
  • 56. Задача о консенсусе • Согласованность (consistent): все потоки должны вернуть одно и то же значение из метода decide • Обоснованность (valid): возвращенное значение было входным значением какого-то из потоков class Consensus: def decide(val): … return decision Будем пытаться реализовать протокол консенсуса используя регистры и другие примитивы  Каждый поток использует объект Consensus один раз
  • 57. Консенсус с блокировкой • Тривиальная реализация протокола консенсуса с помощью взаимного исключения для любого количества потоков • Но мы хотим реализацию без ожидания (wait-free) shared int decision // init NA Mutex mutex def decide(val): mutex.lock() if decision == NA: decision = val mutex.unlock() return decision
  • 58. Консенсусное число • Если с помощью класса [атомарных] объектов C и атомарных регистров (переменных) можно реализовать консенсусный протокол без ожидания (wait-free) для N потоков (и не больше), то говорят что у класса C консенсусное число равно N • ТЕОРЕМА: Атомарные регистры (общие переменные с операциями read/write) имеют консенсусное число 1 - Т.е. с помощью атомарных переменных даже 2 потока не могут придти к консенсусу без ожидания - М. Херлихи, 1991 год
  • 59. Read-Modify-Write регистры • Для функции или класса функций F(args) - getAndSet (exchange), getAndIncrement, getAndAdd и т.п. - get (read) это тоже [тривиальная] RMW операция без дополнительных аргументов для F() == id class RMWRegister: private shared int reg def read(): return reg def getAndF(args): do atomically: old = reg reg = F(args)(reg) return old
  • 60. Нетривиальные RMW регистры • Консенсусное число нетривиального RMW регистра >= 2 - Нужно чтобы была хотя бы одна «подвижная» точка функции F, например F(v0) == v1 != v0 threadlocal int id // 0 or 1 shared RMWRegister rmw shared int proposed[2] def decide(val): proposed[id] = val if rmw.getAndF() == v0: return proposed[i] else: return proposed[1-i] Реализация протокола для 2-х потоков
  • 61. Common2 RMW регистры • Определения - F1 и F2 коммутируют если F1(F2(x)) == F2(F1(x)) - F1 перезаписывает F2 если F1(F2(x)) == F1(x) - Класс С RMW регистров принадлежит Common2, если любая пара функций либо коммутирует, либо одна из функций перезаписывает другую • ТЕОРЕМА: Нетривиальный класс Common2 RMW регистров имеет консенсусное число 2 - Три потока уже не могут решить задачу консенсуса
  • 62. Универсальные объекты • Объект с консенсусный числом бесконечность называется «универсальный объект». - По определению, с помощью него можно реализовать консенсусный протокол для любого числа потоков class CASRegister: private shared int reg def CAS(expect, update): do atomically: old = reg if old == expect: reg = update return true return false Примеры:  compareAndSet (СAS) aka testAndSet (возвращает boolean)  compareAndExchange aka CMPXCHG (возвращает старое значение как и положено RMW операции)
  • 63. CAS и консенсус def decide(val): if CAS(NA, val): return val else: return read() Реализация протокола через CAS+READ def decide(val): old = CMPXCHG(NA, val): if old == NA: return val else: return old Реализация протокола через CMPXCHG
  • 64. Универсальность консенсуса • ТЕОРЕМА: Любой последовательный объект можно реализовать без ожидания (wait-free) для N потоков используя консенсусный протокол для N объектов - Такое построение называется универсальная конструкция - Следствие 1: С помощью любого класса объектов с консенсусным числом N можно реализовать любой объект с консенсусным числом <= N. - Следствие 2: С помощью универсального объекта можно реализовать вообще любой объект • Cначала реализуем консенсус для любого числа потоков (по определению универсального объекта) • Потом через консенсус любой другой объект используя универсальную конструкцию
  • 65. Иерархия объектов Объект Консенсусное число Атомарные регистры, снимок состояния нескольких регистров 1 getAndSet (атомарный обмен), getAndAdd, очередь (только enqueue/dequeue), стек (только push/pop) 2 Атомарная запись m регистров из m(m+1)/2 регистров m compareAndSet, LoadLinked/StoreConditional, очередь с операций peek, многие другие сложные структуры данных ∞
  • 66. Универсальные операции (на практике это обычно CAS) необходимы для реализации любых нетривиальных структур данных без блокировки
  • 67. Рекомендованная литература В своем блоге elizarov.livejournal.com я размещу ссылки на научные работы для дополнительного чтения по теме
  • 68. Спасибо за внимание Слайды также будут выложены на elizarov.livejournal.com