SlideShare a Scribd company logo
1 of 44
Многопроцессорное
Программирование
Обзорный курс (3-я лекция)
Дмитрий Цителов, 2014
cit@devexperts.com
В курсе использованы материалы из лекций Романа Елизарова и презентационных материалов Devexperts, LLC
Алгоритмы без блокировок
• Условия прогресса
• Регистры без блокировок
• Консенсус
• Детали реализации
Краткое содержание предыдущих серий…
Безусловные условия прогресса
• Условия прогресса
- Obstruction-free – прогресс* одного в отсутствии конкуренции
- Lock-free – прогресс хотя бы одного
- Wait-free – прогресс всех
Используя блокировку (lock) мы не можем получить объект без
блокировки (lock-free) и даже без помех (obstruction-free)
*прогресс = выполнение операции за конечное время
Регистры без блокировок
• Виды
- [Single/Multiple]x[Reader/Writer]
- Safe  Regular  Atomic
- Safe SRSW  Atomic MRMW (wait-free)
• Атомарный снимок N MRSW регистров
- Lock-free
- Wait-free - требует O(N2) памяти
Консенсус
• Протокол консенсуса
• Консенсусное число
- Регистры - 1
- Common2 RMW регистры – 2
- CompareAndSet - ∞ (универсальный объект)
Любой последовательный объект можно реализовать без
ожидания (wait-free) для N потоков используя консенсусный
протокол для N объектов.
class Consensus:
def decide(val):
…
return decision
Java Memory Model
• Отношения synchronizes-with и happens-before
• Data race
• Программный порядок
• Гарантии
- Выполнение корректно синхронизированной программы
будет выглядеть последовательно согласовано.
- Гонки за данными не могут нарушить базовые гарантии
безопасности платформы
• Примитивы синхронизации
- synchronized + wait/notify/notifyAll
- volatile
Подходы к синхронизации для общей структуры
данных
• Типы синхронизации:
- Грубая (Coarse-grained) – «лок на всѐ»
- Тонкая (Fine-grained) - «блокировка мелких частей»
- Оптимистичная (Optimistic) – «поиск-блокировка-проверка»
• Ленивая (Lazy) – проверка локальна
- Неблокирующая (Nonblocking) синхронизация (lock-free, wait-free и
т.п.)
Многопоточные связанные списки
Детали реализации
(продолжение)
http://www.nasparpreservation.net/#!efficient-down-to-the-small-details/
Неблокирующая синхронизация (1)
• Простое использование Compare-And-Set (CAS) не помогает –
удаления двух соседних элементов будут конфликтовать.
- Удаляем одновременно элементы 20 и 37
- Конфликта по изменяемым указателям (зеленые) нет
- Но элемент 37 оказывается в списке после удаления!
Неблокирующая синхронизация (2)
• Объединим next и marked в одну переменную, пару
(next,marked), которую будем атомарно менять используя CAS
- Тогда одновременное удаление двух соседних элементов будет
конфликтовать (элемент 20 в примере удаляется и меняет next)
- Каждая операция модификации будет выполнятся одним
успешным CAS-ом.
- Успешное выполнение CAS-а является точкой линеаризации.
• При выполнении операции удаления или добавления будем
пытаться произвести физическое удаление
- Добавление и удаление будут работать без блокировки (lock-free)
- Поиск элемента будет работать без ожидания (wait-free)
Неблокирующая синхронизация: добавление
// пока это псевдокод… сейчас доведем до Java
retry: while (true) {
// метод find возвращает пару (pred,curr)
(Node pred, Node curr) = find(key);
if (curr.key == key) return false; else {
Node node = new Node(key, item);
node.(next,marked) = (curr,false);
if (CAS(pred.(next,marked), (curr,false),
(node,false))
return true;
}
}
линеаризация
Пара (next,marked) с поддержкой опреции CAS реализуется в Java с
помощью класса java.util.concurrent.atomic.AtomicMarkableReference
Неблокирующая синхронизация: узел
• Напишем настоящую Java реализацию
- Больше не нужен lock.
- AtomicMarkableReference работает как volatile
class Node {
final int key;
final T item;
final AtomicMarkableReference<Node> next;
}
// Так будем возвращать пару узлов из find
class Window {
final Node pred;
final Node curr;
}
AtomicMarkableReference<V>
void set(V reference, boolean mark)
V getReference()
boolean isMarked()
V get(boolean []markHolder) //нет указателей на примитивы
boolean compareAndSet(
V expectedRef, V newRef,
boolean expectedMark, boolean newMark)
boolean attemptMark(V expectedRef, boolean newMark)
Неблокирующая синхронизация: поиск окна
Window find(int key) {
retry: while (true) {
Node pred = head, curr = pred.next.getReference();
boolean[] marked = new boolean[1];
while (true) {
Node succ = curr.next.get(marked);
if (marked[0]) { // Если curr удален
if (!pred.next.compareAndSet(
curr, succ, false, false))
continue retry;
curr = succ;
} else {
if (curr.key >= key)
return new Window(pred, curr);
pred = curr; curr = succ;
}
}}}
усп. поиск
Неблокирующая синхронизация: поиск
• Здесь уже всѐ просто
• Поиск фактически полностью выполняется методом find
- Точка линеаризации успешного поиска это чтение пары
(next,marked) в узле curr
boolean contains(int key) {
Window w = find(key);
return w.curr.key == key;
}
Неблокирующая синхронизация: добавление
// вот так выглядит реальный Java код добавления
retry: while (true) {
Window w = find(key);
Node pred = w.pred, curr = w.curr;
if (curr.key == key) return false; else {
Node node = new Node(key, item);
node.next.set(curr, false);
if (pred.next.compareAndSet(
curr, node, false, false))
return true;
}
}
Неблокирующая синхронизация: удаление
retry: while (true) {
Window w = find(key);
Node pred = w.pred, curr = w.curr;
if (curr.key != key) return false; else {
Node succ = curr.next.getReference();
if (!curr.next.attemptMark(succ, true))
continue retry;
// оптимизация – попытаемся физ. удалить
pred.next.compareAndSet(
curr, succ, false, false);
return true;
}
}
линеаризация
Универсальное построение без блокировок с
использованием CAS
• Вся структура данных представляется как указатель на
объект, содержимое которого никогда не меняется.
• Любые операции чтения работают без ожидания.
• Любые операции модификации создают полную копию
структуры, меняют еѐ, из пытаются подменить указать на неѐ с
помощью одного Compare-And-Set (CAS).
- В случае ошибки CAS – повтор.
• Частный случай этого подхода: вся структура данных влезает
в одно машинное слово, например счетчик.
Атомарный счетчик
int counter;
int getAndIncrement(int increment) {
while (true) {
int old = counter;
int updated = old + increment;
if (CAS(counter, old, updated))
return old;
}
}
// В Java int & CAS это
// java.util.concurrent.atomic.AtomicInteger
// там метод getAndIncrement уже есть
Copy-On-Write список на массиве*
private volatile Object[] array;
int boolean add(E e) {
while(true) {
Object[] old = array;
int len = old.length;
Object[] next =
Arrays.copyOf(next, old.length + 1);
next[len] = e;
if CAS(array, old, next);
return true;
}
}
*Неэффективно, если массив большой или часто меняется
Работа с древовидными структурами без
блокировок
• Структура представлена в виде дерева
• Тогда операции изменения можно реализовать в виде одного
CAS, заменяющего указатель на root дерева.
- Неизменившуюся часть дерева можно использовать в новой
версии дерева, т.е. не нужно копировать всю структуру данных.
- Это т.н. персистентные структуры данных
Персистентная древовидная структура
Root
NodeA NodeB
NodeC NodeD
Update B Root’
NodeB’
oldval newval
LIFO стек
• Частный случай вырожденной древовидной структуры это
LIFO стек
class Node {
// Узел никогда не меняется. Все поля final
// Меняется только корень (top)
final T item;
final Node next;
}
// Пустой стек это указатель на null
// AtomicReferece чтобы делать СAS на ссылкой
final AtomicReferece<Node> top =
new AtomicReference<Node>(null);
Операции с LIFO стеком
void push(T item) {
while (true) {
Node node = new Node(item, top.get());
if (top.compareAndSet(node.next, node))
return;
}
}
T pop() {
while (true) {
Node node = top.get();
if (node == null) throw new EmptyStack();
if (top.compareAndSet(node, node.next))
return node.item;
}
}
FIFO очередь без блокировок (lock-free)
• Так же односвязный список, но два указателя: head и tail.
• Алгоритм придумали Michael & Scott в 1996 году.
class Node {
T item;
final AtomicReference<Node> next;
}
// Пустой список состоит их одного элемента-заглушки
AtomicReference<Node> head =
new AtomicReference<Node>(new Node(null));
AtomicReference<Node> tail =
new AtomicReference<Node>(head.get()) ;
(*) Алгоритм “Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms” by Maged Michael et al
Добавление в очередь
void enqueue(T item) {
Node node = new Node(item);
retry: while (true) {
Node last = tail.get(),
next = last.next.get();
if (next == null) {
if (!last.next.compareAndSet(null, node))
continue retry;
// оптимизация – сами переставляем tail
tail.compareAndSet(last, node);
return;
}
// Помогаем другим операциям enqueue с tail
tail.compareAndSet(last, next);
}
}
линеаризация
Удаление из очереди
T dequeue() {
retry: while (true) {
Node first = head.get(),
last = tail.get(),
next = first.next();
if (first == last) {
if (next == null) throw new EmptyQueue();
// Помогаем операциям enqueue с tail
tail.compareAndSet(last, next);
} else {
if (head.compareAndSet(first, next))
return next.item;
}
}
}
линеаризация
Работа без GC, проблема ABA
• Память освобождается явно через “free” с добавлением в
список свободной памяти:
- Содержимое ячейки может меняться произвольным образом,
пока на неѐ удерживается указатель
• решение – дополнительные перепроверки
- CAS может ошибочно отработать из-за проблемы ABA
• решение – добавление версии к указателю
• Альтернативное решение – свой GC
- Hazard Pointers как одна из специальных техник выявления
указателей, которые можно безопасно освободить
- Либо любой GC типа mark & sweep, копирующий и т.п.
Contention
Проблема: много физических ядер и много потоков + обращения
в одни ячейки  CAS будет заканчиваться неудачей
Решение: усложнение алгоритмов и структур данных.
Например, для построения сумматора может быть использован
набор ячеек, хранящих частичные суммы или использоваться
комбинирующее дерево.
False sharing: Contention возникающий при обращении к разным
переменным (причина: архитектура доступа к памяти
Очереди/стеки на массивах
• Структуры на массивах быстрей работают на практике из-за
локальности доступа к данным
• Очевидные решения не работают
• Неочевидные решения
- Дек без помех (Obstruction-free Deque)
- DCAS/CASn (Обновление нескольких слов одновременно)
- Используя дескрипторы операций (универсальная конструкция)
Дек без помех
• Каждый элемента массива должен содержать элемент и
версию, которые мы будем атомарно обновлять CAS-ом
• Пустые элементы будут заполнены правыми и левыми нулями
(RN и LN)
• Указатели на правый и левый край будут храниться
«приблизительно» и подбираться перед выполнением
операций с помощью оракула (rightOracle и leftOracle)
// массив на MAX элементов (0..MAX-1)
{T item, int ver} a[MAX];
int left, right; // прибл. указатель на LN и RN
(*) Алгоритм “Obstruction-Free Synchronization: Double-Ended Queues as an Example” by Maurice Herlihy et al
Оракул для поиска правого края
// Должен находить такое место что:
// a[k] == RN && a[k – 1] != RN
// Должен корректно работать «без помех»
int rightOracle() {
int k = right; // только для оптимизации
while (a[k] != RN) k++;
while (a[k-1] == RN) k--;
right = k; // запомнили для оптимизации
return k;
}
Добавление справа
void rightPush(T item) {
retry: while(true) {
int k = rightOracle();
{T item,int ver} prev = a[k-1], cur = a[k];
if (prev.item == RN || cur.item != RN) continue;
if (k == MAX-1) throw new FullDeque();
if (CAS(a[k-1], prev, {prev.item,prev.ver+1} &&
CAS(a[k], cur, {item,cur.ver+1})
return; // успешно закончили
}
Удаление справа
T rightPop() {
retry: while(true) {
int k = oracleRight();
{T item,int ver} cur = a[k-1], next = a[k];
if (cur.item == RN || next.item != RN) continue;
if (cur.item == LN) throw new EmptyDeque();
if (CAS(a[k], next, {RN,next.ver+1} &&
CAS(a[k-1], cur, {RN,cur.ver+1})
return cur.item; // успешно закончили
}
Хэш-таблицы с прямой адресацией (1)
• Наивный подход
- Естественный параллелизм,
легко делать раздельные
блокировки/нарезку блокировок
(lock striping) по каждой ячейке
- Применяя алгоритмы работы
со списками/множествами
можно сделать реализацию без
блокировок
• Изменение размера хэш-
таблицы (rehash)
- Проблема. Требует блокировки
Но можно блокировать только запись, читая без ожидания
Хэш-таблицы с прямой адресацией (2)
• Упорядоченные по хэш-коду таблицы Шалева и Шавита
- Использует один отсортированный список без блокировок
- Таблицу ссылок (которая дает O(1) поиск) можно перестраивать
не теряя возможности вносить изменения в основную структуру
данных (список)
(*) Алгоритм “Split-Ordered Lists: Lock-Free Extensible Hash Tables” by Ori Shalev and Nir Shavit
Хэш-таблицы с открытой адресацией (1)
• Чтобы читать без блокировок, надо чтобы
каждый ключ заняв какую-то позицию в
таблице больше никогда еѐ не освобождал и
не перемещался
- Тогда найдя эту позицию можно читать
последнее значение из ячейки без ожидания
• Удаление через пометку (сброс значения)
• Чтобы добавить элементы, почистить
удаленные элементы или увеличить размер
нужна блокировка
- Для всех «структурных изменений»
(что влечет блокировку для всех изменений)
K V
e T
e T
k1 V1
k2 T
e T
e T
e T
Хэш-таблицы с открытой адресацией (2)
• Но можно научиться выделять новую таблицу и отслеживать
процедуру переноса ключа и значения из старой таблицы в
новую таблицу
- У каждого элемента будет свой автомат состояний и переходов
между ними
- Каждый элемент можно будет переносить по-отдельности
• В том числе, разные элементы параллельно
- В процессе переноса нужно помнить указатель и на новую
таблицу и на старую
• Указатель на старую таблицу можно сбросить, когда перенос
завершен
(*) Алгоритм “A Lock-Free Wait-Free Hash Table” by Cliff Click
Общая проблема: построение составных объектов
(composability)
public class Employees { // Небезопасный объект!
Set working =
new ConcurrentSet(); // thread-safe
Set vacating =
new ConcurrentSet(); // thread-safe
public boolean contains(Employee e) {
return working.contains(e) ||
vacating.contains(e);
}
public void startVacation(Employee e) {
working.remove(e);
vacating.add(e);
}
}
Решение: Software* Transactional Memory (STM)
• Классические транзакции:
- Atomicity
- Consistency
- Isolation
- Durability
*Лучше, конечно, Hardware TM (уже появляется поддержка)
Поддержка на уровне языка
// если бы можно было бы написать так…
public boolean contains(Employee e) {
atomic {
return working.contains(e) ||
vacating.contains(e);
}
}
public void startVacation(Employee e) {
atomic {
working.remove(e);
vacating.add(e);
}
}
Вопросы?
Всѐ ещѐ есть вопросы?
cit@devexperts.com

More Related Content

What's hot

ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...Alexey Paznikov
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухинcorehard_by
 
How threads help each other
How threads help each otherHow threads help each other
How threads help each otherAlexey Fyodorov
 
8. java lecture threads
8. java lecture threads8. java lecture threads
8. java lecture threadsMERA_school
 
Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»e-Legion
 
Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6Dima Dzuba
 
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorFedor Lavrentyev
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...Alexey Paznikov
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерSergey Platonov
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
10. java lecture generics&collections
10. java lecture generics&collections10. java lecture generics&collections
10. java lecture generics&collectionsMERA_school
 
Java осень 2013 лекция 2
Java осень 2013 лекция 2Java осень 2013 лекция 2
Java осень 2013 лекция 2Technopark
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Alexey Paznikov
 
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Sigma Software
 

What's hot (19)

ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
 
Zagursky
ZagurskyZagursky
Zagursky
 
How threads help each other
How threads help each otherHow threads help each other
How threads help each other
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
8. java lecture threads
8. java lecture threads8. java lecture threads
8. java lecture threads
 
Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»Владимир Горбенко «Использование блоков в Objective-C»
Владимир Горбенко «Использование блоков в Objective-C»
 
Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6
 
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Java 8 puzzlers
Java 8 puzzlersJava 8 puzzlers
Java 8 puzzlers
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
10. java lecture generics&collections
10. java lecture generics&collections10. java lecture generics&collections
10. java lecture generics&collections
 
Java осень 2013 лекция 2
Java осень 2013 лекция 2Java осень 2013 лекция 2
Java осень 2013 лекция 2
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
 

Viewers also liked

Da recorribilidade das decisões do relator no recurso de agravo
Da recorribilidade das decisões do relator no recurso de agravoDa recorribilidade das decisões do relator no recurso de agravo
Da recorribilidade das decisões do relator no recurso de agravoGil Caldas
 
Henriksen Auto - Brosjyre 2016
Henriksen Auto -  Brosjyre 2016Henriksen Auto -  Brosjyre 2016
Henriksen Auto - Brosjyre 2016HenriksenAutoAS
 
delete_blood_cancer_dkms_2014_at_a_glance_3
delete_blood_cancer_dkms_2014_at_a_glance_3delete_blood_cancer_dkms_2014_at_a_glance_3
delete_blood_cancer_dkms_2014_at_a_glance_3Penina Seidman
 
Homeopatia 58 casos Veterinária
Homeopatia   58 casos VeterináriaHomeopatia   58 casos Veterinária
Homeopatia 58 casos VeterináriaMeybe Regina
 
Mobile Learning and Health Risks - Implications for Pedagogical and Education...
Mobile Learning and Health Risks - Implications for Pedagogical and Education...Mobile Learning and Health Risks - Implications for Pedagogical and Education...
Mobile Learning and Health Risks - Implications for Pedagogical and Education...Mikko Ahonen
 
Graham Dukes - Selling Sickness 2010
Graham Dukes - Selling Sickness 2010Graham Dukes - Selling Sickness 2010
Graham Dukes - Selling Sickness 2010Gezonde scepsis
 
Eine weldenwandeling
Eine weldenwandelingEine weldenwandeling
Eine weldenwandelingraoulv
 
Brand Identity and Social Media
Brand Identity and Social MediaBrand Identity and Social Media
Brand Identity and Social MediaSimone Moriconi
 
Machine Learning Search and SEO - Zenith; Duluth, MN.
Machine Learning Search and SEO - Zenith; Duluth, MN. Machine Learning Search and SEO - Zenith; Duluth, MN.
Machine Learning Search and SEO - Zenith; Duluth, MN. Eric Enge
 
Final BTC Presentation 2.0
Final BTC Presentation 2.0Final BTC Presentation 2.0
Final BTC Presentation 2.0Julia Barros
 

Viewers also liked (12)

Da recorribilidade das decisões do relator no recurso de agravo
Da recorribilidade das decisões do relator no recurso de agravoDa recorribilidade das decisões do relator no recurso de agravo
Da recorribilidade das decisões do relator no recurso de agravo
 
Henriksen Auto - Brosjyre 2016
Henriksen Auto -  Brosjyre 2016Henriksen Auto -  Brosjyre 2016
Henriksen Auto - Brosjyre 2016
 
delete_blood_cancer_dkms_2014_at_a_glance_3
delete_blood_cancer_dkms_2014_at_a_glance_3delete_blood_cancer_dkms_2014_at_a_glance_3
delete_blood_cancer_dkms_2014_at_a_glance_3
 
Homeopatia 58 casos Veterinária
Homeopatia   58 casos VeterináriaHomeopatia   58 casos Veterinária
Homeopatia 58 casos Veterinária
 
Mobile Learning and Health Risks - Implications for Pedagogical and Education...
Mobile Learning and Health Risks - Implications for Pedagogical and Education...Mobile Learning and Health Risks - Implications for Pedagogical and Education...
Mobile Learning and Health Risks - Implications for Pedagogical and Education...
 
Stats - Intro to Quantitative
Stats -  Intro to Quantitative Stats -  Intro to Quantitative
Stats - Intro to Quantitative
 
Graham Dukes - Selling Sickness 2010
Graham Dukes - Selling Sickness 2010Graham Dukes - Selling Sickness 2010
Graham Dukes - Selling Sickness 2010
 
Joel
JoelJoel
Joel
 
Eine weldenwandeling
Eine weldenwandelingEine weldenwandeling
Eine weldenwandeling
 
Brand Identity and Social Media
Brand Identity and Social MediaBrand Identity and Social Media
Brand Identity and Social Media
 
Machine Learning Search and SEO - Zenith; Duluth, MN.
Machine Learning Search and SEO - Zenith; Duluth, MN. Machine Learning Search and SEO - Zenith; Duluth, MN.
Machine Learning Search and SEO - Zenith; Duluth, MN.
 
Final BTC Presentation 2.0
Final BTC Presentation 2.0Final BTC Presentation 2.0
Final BTC Presentation 2.0
 

Similar to Multiprocessor Programming Intro (lecture 3)

Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"LogeekNightUkraine
 
Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2Technopark
 
Обзор ES2015(ES6)
Обзор ES2015(ES6)Обзор ES2015(ES6)
Обзор ES2015(ES6)Alex Filatov
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?Vasil Remeniuk
 
05 - Java. Collections Framework и Generics
05 - Java. Collections Framework и Generics05 - Java. Collections Framework и Generics
05 - Java. Collections Framework и GenericsRoman Brovko
 
C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному кодуVasiliy Deynega
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Vasya Petrov
 
Очень вкусный фрукт Guava
Очень вкусный фрукт GuavaОчень вкусный фрукт Guava
Очень вкусный фрукт GuavaEgor Chernyshev
 
Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Alex Tumanoff
 
Внутреннее устройство и оптимизация бандла webpack
Внутреннее устройство и оптимизация бандла webpackВнутреннее устройство и оптимизация бандла webpack
Внутреннее устройство и оптимизация бандла webpackAlexey Ivanov
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey TeplyakovAlex Tumanoff
 
Alexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher SqlAlexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher SqlAlexander Dymo
 
Adymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher SqlAdymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher SqlOleksandr Petrov
 
Типичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverТипичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverIgor Khrol
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Vasya Petrov
 

Similar to Multiprocessor Programming Intro (lecture 3) (20)

Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"Sergii Tsypanov "Performance 1001 Tips"
Sergii Tsypanov "Performance 1001 Tips"
 
Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2Алгоритмы и структуры данных осень 2013 лекция 2
Алгоритмы и структуры данных осень 2013 лекция 2
 
Обзор ES2015(ES6)
Обзор ES2015(ES6)Обзор ES2015(ES6)
Обзор ES2015(ES6)
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?
 
05 - Java. Collections Framework и Generics
05 - Java. Collections Framework и Generics05 - Java. Collections Framework и Generics
05 - Java. Collections Framework и Generics
 
C#. От основ к эффективному коду
C#. От основ к эффективному кодуC#. От основ к эффективному коду
C#. От основ к эффективному коду
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
 
Очень вкусный фрукт Guava
Очень вкусный фрукт GuavaОчень вкусный фрукт Guava
Очень вкусный фрукт Guava
 
Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2
 
Внутреннее устройство и оптимизация бандла webpack
Внутреннее устройство и оптимизация бандла webpackВнутреннее устройство и оптимизация бандла webpack
Внутреннее устройство и оптимизация бандла webpack
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey Teplyakov
 
Presentation_1369080393540
Presentation_1369080393540Presentation_1369080393540
Presentation_1369080393540
 
Alexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher SqlAlexander Dymo - Barcamp 2009 - Faster Higher Sql
Alexander Dymo - Barcamp 2009 - Faster Higher Sql
 
Adymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher SqlAdymo Barcamp Presentation Faster Higher Sql
Adymo Barcamp Presentation Faster Higher Sql
 
Типичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverТипичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriver
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
 
Lec 3
Lec 3Lec 3
Lec 3
 
Intro to Swift techitout
Intro to Swift techitoutIntro to Swift techitout
Intro to Swift techitout
 

Multiprocessor Programming Intro (lecture 3)

  • 1. Многопроцессорное Программирование Обзорный курс (3-я лекция) Дмитрий Цителов, 2014 cit@devexperts.com В курсе использованы материалы из лекций Романа Елизарова и презентационных материалов Devexperts, LLC
  • 2. Алгоритмы без блокировок • Условия прогресса • Регистры без блокировок • Консенсус • Детали реализации Краткое содержание предыдущих серий…
  • 3. Безусловные условия прогресса • Условия прогресса - Obstruction-free – прогресс* одного в отсутствии конкуренции - Lock-free – прогресс хотя бы одного - Wait-free – прогресс всех Используя блокировку (lock) мы не можем получить объект без блокировки (lock-free) и даже без помех (obstruction-free) *прогресс = выполнение операции за конечное время
  • 4. Регистры без блокировок • Виды - [Single/Multiple]x[Reader/Writer] - Safe  Regular  Atomic - Safe SRSW  Atomic MRMW (wait-free) • Атомарный снимок N MRSW регистров - Lock-free - Wait-free - требует O(N2) памяти
  • 5. Консенсус • Протокол консенсуса • Консенсусное число - Регистры - 1 - Common2 RMW регистры – 2 - CompareAndSet - ∞ (универсальный объект) Любой последовательный объект можно реализовать без ожидания (wait-free) для N потоков используя консенсусный протокол для N объектов. class Consensus: def decide(val): … return decision
  • 6. Java Memory Model • Отношения synchronizes-with и happens-before • Data race • Программный порядок • Гарантии - Выполнение корректно синхронизированной программы будет выглядеть последовательно согласовано. - Гонки за данными не могут нарушить базовые гарантии безопасности платформы • Примитивы синхронизации - synchronized + wait/notify/notifyAll - volatile
  • 7. Подходы к синхронизации для общей структуры данных • Типы синхронизации: - Грубая (Coarse-grained) – «лок на всѐ» - Тонкая (Fine-grained) - «блокировка мелких частей» - Оптимистичная (Optimistic) – «поиск-блокировка-проверка» • Ленивая (Lazy) – проверка локальна - Неблокирующая (Nonblocking) синхронизация (lock-free, wait-free и т.п.)
  • 10. Неблокирующая синхронизация (1) • Простое использование Compare-And-Set (CAS) не помогает – удаления двух соседних элементов будут конфликтовать. - Удаляем одновременно элементы 20 и 37 - Конфликта по изменяемым указателям (зеленые) нет - Но элемент 37 оказывается в списке после удаления!
  • 11. Неблокирующая синхронизация (2) • Объединим next и marked в одну переменную, пару (next,marked), которую будем атомарно менять используя CAS - Тогда одновременное удаление двух соседних элементов будет конфликтовать (элемент 20 в примере удаляется и меняет next) - Каждая операция модификации будет выполнятся одним успешным CAS-ом. - Успешное выполнение CAS-а является точкой линеаризации. • При выполнении операции удаления или добавления будем пытаться произвести физическое удаление - Добавление и удаление будут работать без блокировки (lock-free) - Поиск элемента будет работать без ожидания (wait-free)
  • 12. Неблокирующая синхронизация: добавление // пока это псевдокод… сейчас доведем до Java retry: while (true) { // метод find возвращает пару (pred,curr) (Node pred, Node curr) = find(key); if (curr.key == key) return false; else { Node node = new Node(key, item); node.(next,marked) = (curr,false); if (CAS(pred.(next,marked), (curr,false), (node,false)) return true; } } линеаризация Пара (next,marked) с поддержкой опреции CAS реализуется в Java с помощью класса java.util.concurrent.atomic.AtomicMarkableReference
  • 13. Неблокирующая синхронизация: узел • Напишем настоящую Java реализацию - Больше не нужен lock. - AtomicMarkableReference работает как volatile class Node { final int key; final T item; final AtomicMarkableReference<Node> next; } // Так будем возвращать пару узлов из find class Window { final Node pred; final Node curr; }
  • 14. AtomicMarkableReference<V> void set(V reference, boolean mark) V getReference() boolean isMarked() V get(boolean []markHolder) //нет указателей на примитивы boolean compareAndSet( V expectedRef, V newRef, boolean expectedMark, boolean newMark) boolean attemptMark(V expectedRef, boolean newMark)
  • 15. Неблокирующая синхронизация: поиск окна Window find(int key) { retry: while (true) { Node pred = head, curr = pred.next.getReference(); boolean[] marked = new boolean[1]; while (true) { Node succ = curr.next.get(marked); if (marked[0]) { // Если curr удален if (!pred.next.compareAndSet( curr, succ, false, false)) continue retry; curr = succ; } else { if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; } }}} усп. поиск
  • 16. Неблокирующая синхронизация: поиск • Здесь уже всѐ просто • Поиск фактически полностью выполняется методом find - Точка линеаризации успешного поиска это чтение пары (next,marked) в узле curr boolean contains(int key) { Window w = find(key); return w.curr.key == key; }
  • 17. Неблокирующая синхронизация: добавление // вот так выглядит реальный Java код добавления retry: while (true) { Window w = find(key); Node pred = w.pred, curr = w.curr; if (curr.key == key) return false; else { Node node = new Node(key, item); node.next.set(curr, false); if (pred.next.compareAndSet( curr, node, false, false)) return true; } }
  • 18. Неблокирующая синхронизация: удаление retry: while (true) { Window w = find(key); Node pred = w.pred, curr = w.curr; if (curr.key != key) return false; else { Node succ = curr.next.getReference(); if (!curr.next.attemptMark(succ, true)) continue retry; // оптимизация – попытаемся физ. удалить pred.next.compareAndSet( curr, succ, false, false); return true; } } линеаризация
  • 19. Универсальное построение без блокировок с использованием CAS • Вся структура данных представляется как указатель на объект, содержимое которого никогда не меняется. • Любые операции чтения работают без ожидания. • Любые операции модификации создают полную копию структуры, меняют еѐ, из пытаются подменить указать на неѐ с помощью одного Compare-And-Set (CAS). - В случае ошибки CAS – повтор. • Частный случай этого подхода: вся структура данных влезает в одно машинное слово, например счетчик.
  • 20. Атомарный счетчик int counter; int getAndIncrement(int increment) { while (true) { int old = counter; int updated = old + increment; if (CAS(counter, old, updated)) return old; } } // В Java int & CAS это // java.util.concurrent.atomic.AtomicInteger // там метод getAndIncrement уже есть
  • 21. Copy-On-Write список на массиве* private volatile Object[] array; int boolean add(E e) { while(true) { Object[] old = array; int len = old.length; Object[] next = Arrays.copyOf(next, old.length + 1); next[len] = e; if CAS(array, old, next); return true; } } *Неэффективно, если массив большой или часто меняется
  • 22. Работа с древовидными структурами без блокировок • Структура представлена в виде дерева • Тогда операции изменения можно реализовать в виде одного CAS, заменяющего указатель на root дерева. - Неизменившуюся часть дерева можно использовать в новой версии дерева, т.е. не нужно копировать всю структуру данных. - Это т.н. персистентные структуры данных
  • 23. Персистентная древовидная структура Root NodeA NodeB NodeC NodeD Update B Root’ NodeB’ oldval newval
  • 24. LIFO стек • Частный случай вырожденной древовидной структуры это LIFO стек class Node { // Узел никогда не меняется. Все поля final // Меняется только корень (top) final T item; final Node next; } // Пустой стек это указатель на null // AtomicReferece чтобы делать СAS на ссылкой final AtomicReferece<Node> top = new AtomicReference<Node>(null);
  • 25. Операции с LIFO стеком void push(T item) { while (true) { Node node = new Node(item, top.get()); if (top.compareAndSet(node.next, node)) return; } } T pop() { while (true) { Node node = top.get(); if (node == null) throw new EmptyStack(); if (top.compareAndSet(node, node.next)) return node.item; } }
  • 26. FIFO очередь без блокировок (lock-free) • Так же односвязный список, но два указателя: head и tail. • Алгоритм придумали Michael & Scott в 1996 году. class Node { T item; final AtomicReference<Node> next; } // Пустой список состоит их одного элемента-заглушки AtomicReference<Node> head = new AtomicReference<Node>(new Node(null)); AtomicReference<Node> tail = new AtomicReference<Node>(head.get()) ; (*) Алгоритм “Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms” by Maged Michael et al
  • 27. Добавление в очередь void enqueue(T item) { Node node = new Node(item); retry: while (true) { Node last = tail.get(), next = last.next.get(); if (next == null) { if (!last.next.compareAndSet(null, node)) continue retry; // оптимизация – сами переставляем tail tail.compareAndSet(last, node); return; } // Помогаем другим операциям enqueue с tail tail.compareAndSet(last, next); } } линеаризация
  • 28. Удаление из очереди T dequeue() { retry: while (true) { Node first = head.get(), last = tail.get(), next = first.next(); if (first == last) { if (next == null) throw new EmptyQueue(); // Помогаем операциям enqueue с tail tail.compareAndSet(last, next); } else { if (head.compareAndSet(first, next)) return next.item; } } } линеаризация
  • 29. Работа без GC, проблема ABA • Память освобождается явно через “free” с добавлением в список свободной памяти: - Содержимое ячейки может меняться произвольным образом, пока на неѐ удерживается указатель • решение – дополнительные перепроверки - CAS может ошибочно отработать из-за проблемы ABA • решение – добавление версии к указателю • Альтернативное решение – свой GC - Hazard Pointers как одна из специальных техник выявления указателей, которые можно безопасно освободить - Либо любой GC типа mark & sweep, копирующий и т.п.
  • 30. Contention Проблема: много физических ядер и много потоков + обращения в одни ячейки  CAS будет заканчиваться неудачей Решение: усложнение алгоритмов и структур данных. Например, для построения сумматора может быть использован набор ячеек, хранящих частичные суммы или использоваться комбинирующее дерево. False sharing: Contention возникающий при обращении к разным переменным (причина: архитектура доступа к памяти
  • 31. Очереди/стеки на массивах • Структуры на массивах быстрей работают на практике из-за локальности доступа к данным • Очевидные решения не работают • Неочевидные решения - Дек без помех (Obstruction-free Deque) - DCAS/CASn (Обновление нескольких слов одновременно) - Используя дескрипторы операций (универсальная конструкция)
  • 32. Дек без помех • Каждый элемента массива должен содержать элемент и версию, которые мы будем атомарно обновлять CAS-ом • Пустые элементы будут заполнены правыми и левыми нулями (RN и LN) • Указатели на правый и левый край будут храниться «приблизительно» и подбираться перед выполнением операций с помощью оракула (rightOracle и leftOracle) // массив на MAX элементов (0..MAX-1) {T item, int ver} a[MAX]; int left, right; // прибл. указатель на LN и RN (*) Алгоритм “Obstruction-Free Synchronization: Double-Ended Queues as an Example” by Maurice Herlihy et al
  • 33. Оракул для поиска правого края // Должен находить такое место что: // a[k] == RN && a[k – 1] != RN // Должен корректно работать «без помех» int rightOracle() { int k = right; // только для оптимизации while (a[k] != RN) k++; while (a[k-1] == RN) k--; right = k; // запомнили для оптимизации return k; }
  • 34. Добавление справа void rightPush(T item) { retry: while(true) { int k = rightOracle(); {T item,int ver} prev = a[k-1], cur = a[k]; if (prev.item == RN || cur.item != RN) continue; if (k == MAX-1) throw new FullDeque(); if (CAS(a[k-1], prev, {prev.item,prev.ver+1} && CAS(a[k], cur, {item,cur.ver+1}) return; // успешно закончили }
  • 35. Удаление справа T rightPop() { retry: while(true) { int k = oracleRight(); {T item,int ver} cur = a[k-1], next = a[k]; if (cur.item == RN || next.item != RN) continue; if (cur.item == LN) throw new EmptyDeque(); if (CAS(a[k], next, {RN,next.ver+1} && CAS(a[k-1], cur, {RN,cur.ver+1}) return cur.item; // успешно закончили }
  • 36. Хэш-таблицы с прямой адресацией (1) • Наивный подход - Естественный параллелизм, легко делать раздельные блокировки/нарезку блокировок (lock striping) по каждой ячейке - Применяя алгоритмы работы со списками/множествами можно сделать реализацию без блокировок • Изменение размера хэш- таблицы (rehash) - Проблема. Требует блокировки Но можно блокировать только запись, читая без ожидания
  • 37. Хэш-таблицы с прямой адресацией (2) • Упорядоченные по хэш-коду таблицы Шалева и Шавита - Использует один отсортированный список без блокировок - Таблицу ссылок (которая дает O(1) поиск) можно перестраивать не теряя возможности вносить изменения в основную структуру данных (список) (*) Алгоритм “Split-Ordered Lists: Lock-Free Extensible Hash Tables” by Ori Shalev and Nir Shavit
  • 38. Хэш-таблицы с открытой адресацией (1) • Чтобы читать без блокировок, надо чтобы каждый ключ заняв какую-то позицию в таблице больше никогда еѐ не освобождал и не перемещался - Тогда найдя эту позицию можно читать последнее значение из ячейки без ожидания • Удаление через пометку (сброс значения) • Чтобы добавить элементы, почистить удаленные элементы или увеличить размер нужна блокировка - Для всех «структурных изменений» (что влечет блокировку для всех изменений) K V e T e T k1 V1 k2 T e T e T e T
  • 39. Хэш-таблицы с открытой адресацией (2) • Но можно научиться выделять новую таблицу и отслеживать процедуру переноса ключа и значения из старой таблицы в новую таблицу - У каждого элемента будет свой автомат состояний и переходов между ними - Каждый элемент можно будет переносить по-отдельности • В том числе, разные элементы параллельно - В процессе переноса нужно помнить указатель и на новую таблицу и на старую • Указатель на старую таблицу можно сбросить, когда перенос завершен (*) Алгоритм “A Lock-Free Wait-Free Hash Table” by Cliff Click
  • 40. Общая проблема: построение составных объектов (composability) public class Employees { // Небезопасный объект! Set working = new ConcurrentSet(); // thread-safe Set vacating = new ConcurrentSet(); // thread-safe public boolean contains(Employee e) { return working.contains(e) || vacating.contains(e); } public void startVacation(Employee e) { working.remove(e); vacating.add(e); } }
  • 41. Решение: Software* Transactional Memory (STM) • Классические транзакции: - Atomicity - Consistency - Isolation - Durability *Лучше, конечно, Hardware TM (уже появляется поддержка)
  • 42. Поддержка на уровне языка // если бы можно было бы написать так… public boolean contains(Employee e) { atomic { return working.contains(e) || vacating.contains(e); } } public void startVacation(Employee e) { atomic { working.remove(e); vacating.add(e); } }
  • 44. Всѐ ещѐ есть вопросы? cit@devexperts.com

Editor's Notes

  1. CopyOnWrite array
  2. для поддержки версионированных указателей в процессорах предусмотрены команды CAS для слов двойной длинны по отношению к размеру указателя, например CMPXCHG16B (для 64-битного режима)Hazard Pointers – SWMR список указателейна каждый поток, операции удаления с которыми откладываются до освобождения указателя