SlideShare a Scribd company logo
Concurrent mapS
C++ Russia 2015Maxim Khizhinsky
Lock-free hash tableLock-free hash table
LIBCDS
Максим Хижинский, C++ Russia 2015
0 1 2 3 4 5 6
X X X
k1
k
k
k k
k
kk
k
k
2
3
4 5
6
7
8
9
T[8]
Lock-free
список
коллизий
7
k
10
Lock-free ordered listLock-free ordered list
LIBCDS
Максим Хижинский, C++ Russia 2015
Операции:
●
insert( node )
● erase( key )
●
find( key )
template <class T>
struct node {
std::atomic<node*> next_;
T data_;
};
H T52 8
Lock-free примитивы:
● atomic load/store
●
atomic compare-and-swap (CAS)
CAS — compare-and-swapCAS — compare-and-swap
LIBCDS
Максим Хижинский, C++ Russia 2015
template <typename T>
bool CAS( T * pAtomic, T expected, T desired )
atomically {
if ( *pAtomic == expected ) {
*pAtomic = desired;
return true;
}
else
return false;
};
Lock-free list: insertLock-free list: insert
LIBCDS
Максим Хижинский, C++ Russia 2015
H T52 8
3
H T52 8
3
3. prev->next_.CAS( next, new_node )
1. find insert position for key 3
2. new_node.next_.store( next )
H T52 8
prev next
new_node
Lock-free list: eraseLock-free list: erase
LIBCDS
Максим Хижинский, C++ Russia 2015
1. find key 3
2. prev->next_.CAS( found, next )
H T52 8
prev
3
found
H T52 83
Проблема: параллельный insert
next
Lock-free list: insert/eraseLock-free list: insert/erase
LIBCDS
Максим Хижинский, C++ Russia 2015
A: find key 3
H T52 8
prev
3
found
B: find insert pos for key 4
iprev inext
A: erase key 3
H T52 83
prev->next_.CAS( found, next )
next
B: insert key 4
H T52 83
4
iprev->next_.CAS( inext, new_item )
local vars
Marked pointerMarked pointer
LIBCDS
Максим Хижинский, C++ Russia 2015
[ T.Harris, 2001 ]
Двухфазное удаление:
● Логическое удаление — помечаем элемент
●
Физическое удаление — исключаем элемент
В качестве метки используем младший бит указателя
Lock-free list: marked pointerLock-free list: marked pointer
LIBCDS
Максим Хижинский, C++ Russia 2015
H T52 8
prev
3
found
iprev inext
nextA: erase
B: insert
A: Logical deletion - mark item found
H T52 83
found->next_.CAS( next, next | 1 )
B: iprev->next_.CAS( inext, new_item ) - failed!!!
A: Physical deletion - remove item found
H T52 83
prev->next_.CAS( found, next )
Lock-free list: problemsLock-free list: problems
LIBCDS
Максим Хижинский, C++ Russia 2015
H T52 8
prev
3
found
iprev inext
nextA: erase
B: insert
iprev->next_.CAS( inext, new_item )
prev->next_.CAS( found, next )
local vars
Вдруг уже удалены?..
Lock-free list: problemsLock-free list: problems
LIBCDS
Максим Хижинский, C++ Russia 2015
Проблемы:
●
Защита локальных данных — когда элемент можно
безопасно удалить?
●
ABA-проблема
ABA-проблемаABA-проблема
LIBCDS
Максим Хижинский, C++ Russia 2015
52
prev
3
found next
Thread A: erase(3) Thread B
52 3
erase(3); erase(5)
2 3
insert(4)
Heap
new node(4) alloc
delete
42
preempted...
42
prev found next
5
addr(3) == addr(4)
prev->next_.CAS( found, next ) - success!!!
2 мусор
SMRSMR
LIBCDS
Максим Хижинский, C++ Russia 2015
Проблемы:
● Защита локальных данных — когда элемент можно
безопасно удалить?
●
ABA-проблема
Решение:
Safe memory reclamation (SMR)
● Tagged pointers
●
Hazard Pointers
●
User-space RCU
Tagged pointersTagged pointers
LIBCDS
Максим Хижинский, C++ Russia 2015
pointer tag
prev->next_.dwCAS( found, <next.ptr, prev->next_.tag + 1> )
template <class T>
struct tagged_ptr {
T * ptr;
uintptr_t tag;
};
Требует dwCAS — не везде есть
Решает только ABA-проблему
Освободить память нельзя,
нужен free-list
[ boost.lock-free ]
H T52 8
prev
3
found next
Tagged pointers: historyTagged pointers: history
LIBCDS
Максим Хижинский, C++ Russia 2015
ABA-проблема характерна только для CAS
Архитектуры процессоров
LL/SC:
●
IBM PowerPC
● MIPS
●
ARM
➢ LL — load linked
➢ SC — store conditional
bool weak_CAS( T * ptr,
T expected, T desired )
{ T cur = LL( ptr );
return cur == expected
&& SC( ptr, desired );
}
Эмуляция LL/SC на CAS
— намного труднее
CAS:
●
x86, amd64
● Sparc
●
Itanium
С++11 — только CAS
Hazard pointersHazard pointers
LIBCDS
Максим Хижинский, C++ Russia 2015
✔ Использует только атомарные чтение/запись
 Защищает только локальные ссылки
✔ Размер массива отложенных (готовых к
удалению) элементов ограничен сверху
 Перед работой с указателем его следует
объявить как hazard
решает ABA-проблему
Физическое удаление элементов
Hazard pointersHazard pointers
LIBCDS
Максим Хижинский, C++ Russia 2015
H T52 8
prev
3
found next
erase( Key k ) {
hp_guard h1 = get_guard();
hp_guard h2 = get_guard();
retry:
node * prev = Head;
do {
node * found = h2.protect( prev->next_);
if ( found->key == k )
if (prev->next_.CAS( found, found->next_)) {
hp_retire( found );
return true;
}
else
goto retry;
h1 = h2;
prev = found;
} while ( found->key < k );
return false;
}
Распределяем HP (TLS)
Защищаем элемент
Удаляем элемент
Hazard pointersHazard pointers
LIBCDS
Максим Хижинский, C++ Russia 2015
P – thread count
Thread 0
Thread HP Manager
0
1
…
K - 1
HP[K]
0
1
2
…
R - 1
Retired[R]
Hazard Pointer Singleton
Thread
1
Thread
P - 1
K = 4 R = 2 KP
<K,P, R> : R > K * P
Hazard PointersHazard Pointers
LIBCDS
Максим Хижинский, C++ Russia 2015
Объявление Hazard Pointer'а – защита локальной ссылки
class hp_guard {
void * hp;
// ...
};
T * hp_guard::protect(
std::atomic<T*>& what) {
T * t;
do {
hp = t = what.load();
} while (t != what.load());
return t;
}
0
1
…
K - 1
HP[K]
Hazard PointersHazard Pointers
LIBCDS
Максим Хижинский, C++ Russia 2015
Удаление элемента
void hp_retire( T * what ) {
push what to current_thread.Retired array
if ( current_thread.Retired is full )
hp.Scan( current_thread );
}
void hp::Scan() {
void * guarded[K*P] = union HP[K] for all P thread;
foreach ( p in current_thread.Retired[R] )
if ( p not in guarded[] )
delete p;
}
<K,P, R> : R > K * P
0
1
2
…
R - 1
Retired[R]
0
1
…
K - 1
HP[K]
User-space Read-Copy UpdateUser-space Read-Copy Update
LIBCDS
Максим Хижинский, C++ Russia 2015
✔ RCU — метод синхронизации:
RCU.lock() / RCU.unlock()
✔ Разработан для почти-read-only данных (map, set)
✔ Очень легкие read-side lock
✔ Удаление элемента — ожидание окончания эпохи
решает ABA-проблему
Физическое удаление элементов
RCU.lock(): ничего не блокирует
Объявляет, что поток входит в
текущую RCU-эпоху
User-space RCUUser-space RCU
LIBCDS
Максим Хижинский, C++ Russia 2015
Map.find( ... );
Set.insert( ... );
Map.find( ... );
Map.erase( ... )...
Thread 1
Set.find( ... );
Map.insert( ... );
Set.find( ... );
Set.insert( ... );
Thread N
Эпоха 1
RCU.sync() - ждем, пока все потоки покинут эпоху 1
Set.find( ... );
Map.insert( ... );
Set.find( ... );
Set.insert( ... );
... Map.erase;
Map.find( ... );
Set.insert( ... );
Map.find( ... );
++Эпоха
Эпоха 2
Lock-free hash tableLock-free hash table
LIBCDS
Максим Хижинский, C++ Russia 2015
0 1 2 3 4 5 6
X X X
k1
k
k
k k
k
kk
k
k
2
3
4 5
6
7
8
9
T[8]
Lock-free
cписок:
HP/RCU
+ marked
pointers
7
k
10
Hash table + Lock-free ordered list
No rehashing
Split-ordered listSplit-ordered list
LIBCDS
Максим Хижинский, C++ Russia 2015
0 8 2 1 9 13
T[0]
T[1]
k iSentinel node Regular node
N = 2 size() = 4
Load factor L: size() / N ≤ L
Если L = 2, то вставка нового элемента приводит к увеличению
hash table
Hash table
Lock-free ordered list
Skip listSkip list
LIBCDS
Максим Хижинский, C++ Russia 2015
X
X
X
X
X
X
X
X10 15 23 34 5542
23
Tower
h = 3
Вероятностная структура данных:
P[ h == 1 ] = 1/2
P[ h == k ] = 1/2
k
, 0 < k < 32
h = lsb( rand() )
O(log(N))
PerformancePerformance
LIBCDS
Максим Хижинский, C++ Russia 2015
Intel Dual Xeon X5670 2.93 GHz 12 cores 24 threads / 24 GB RAM
Concurrent mapsConcurrent maps
Максим Хижинский, C++ Russia 2015
Спасибо за внимание!
libcds.dev@gmail.com
https://github.com/khizmax/libcds

More Related Content

PDF
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
PDF
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
PDF
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
PDF
Продолжаем говорить о микрооптимизациях .NET-приложений
PDF
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
PDF
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
PDF
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
PDF
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Григорий Демченко, “Асинхронность и сопрограммы: обработка данных“
Продолжаем говорить о микрооптимизациях .NET-приложений
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...

What's hot (20)

PDF
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
PDF
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
PDF
Распространённые ошибки оценки производительности .NET-приложений
PDF
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
PPTX
разработка серверов и серверных приложений лекция №3
PDF
Tech Talks @NSU: Как приручить дракона: введение в LLVM
PDF
Поговорим о микрооптимизациях .NET-приложений
PPTX
разработка серверов и серверных приложений лекция №2
PDF
Поговорим про арифметику
PDF
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
PPTX
Михаил Матросов, “С++ без new и delete”
PDF
Догнать и перегнать boost::lexical_cast
PDF
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
PDF
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
PDF
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
PDF
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
PDF
Лекция 8. Intel Threading Building Blocks
PDF
Конкурентные ассоциативные контейнеры
PDF
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
PPTX
Григорий Демченко, Асинхронность и неблокирующая синхронизация
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
Распространённые ошибки оценки производительности .NET-приложений
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
разработка серверов и серверных приложений лекция №3
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Поговорим о микрооптимизациях .NET-приложений
разработка серверов и серверных приложений лекция №2
Поговорим про арифметику
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
Михаил Матросов, “С++ без new и delete”
Догнать и перегнать boost::lexical_cast
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
Лекция 8. Intel Threading Building Blocks
Конкурентные ассоциативные контейнеры
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Ad

Similar to Максим Хижинский Lock-free maps (20)

PDF
Конкурентные ассоциативные контейнеры
PDF
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
PDF
Практика Lock-free. RealTime-сервер
PDF
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
PDF
Обработка потока данных на примере deep packet inspection: внутренняя архитек...
PDF
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
PDF
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
PDF
20130429 dynamic c_c++_program_analysis-alexey_samsonov
PPT
Как построить высокопроизводительный Front-end сервер (Александр Крижановский)
PDF
Сергей Жгировский — С++11/14 в STL
PDF
Дмитрий Прокопцев "Memory-mapped storage: ещё один подход к сериализации данных"
PDF
Константин Осипов
PPTX
Multiprocessor Programming Intro (lecture 3)
PDF
Cpp0x Introduction
PPT
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
PPT
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
PPT
PPT
Низкоуровневая Оптимизация (Андрей Аксенов)
PDF
Модель памяти C++ - Андрей Янковский, Яндекс
PPTX
Теория и практика написания безопасного кода на C++
Конкурентные ассоциативные контейнеры
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Практика Lock-free. RealTime-сервер
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Обработка потока данных на примере deep packet inspection: внутренняя архитек...
Оптимизация программ для современных процессоров и Linux, Александр Крижановс...
Разработка высокопроизводительных серверных приложений для Linux/Unix (Алекса...
20130429 dynamic c_c++_program_analysis-alexey_samsonov
Как построить высокопроизводительный Front-end сервер (Александр Крижановский)
Сергей Жгировский — С++11/14 в STL
Дмитрий Прокопцев "Memory-mapped storage: ещё один подход к сериализации данных"
Константин Осипов
Multiprocessor Programming Intro (lecture 3)
Cpp0x Introduction
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Низкоуровневая Оптимизация (Андрей Аксенов)
Модель памяти C++ - Андрей Янковский, Яндекс
Теория и практика написания безопасного кода на C++
Ad

More from Platonov Sergey (20)

PPTX
Евгений Зуев, С++ в России: Стандарт языка и его реализация
PPTX
Алексей Кутумов, C++ без исключений, часть 3
PPTX
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
PPT
Евгений Крутько, Многопоточные вычисления, современный подход.
PDF
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
PPTX
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
PDF
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
PDF
QML\Qt Quick на практике
PDF
Визуализация автомобильных маршрутов
PDF
Функциональный микроскоп: линзы в C++
PDF
C++ exceptions
PPTX
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
PDF
HPX: C++11 runtime система для параллельных и распределённых вычислений
PPTX
Ranges calendar-novosibirsk-2015-08
PDF
Использование maven для сборки больших модульных c++ проектов на примере Odin...
PDF
One definition rule - что это такое, и как с этим жить
PDF
DI в C++ тонкости и нюансы
PPTX
Аскетичная разработка браузера
PDF
Concepts lite
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Алексей Кутумов, C++ без исключений, часть 3
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Крутько, Многопоточные вычисления, современный подход.
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
QML\Qt Quick на практике
Визуализация автомобильных маршрутов
Функциональный микроскоп: линзы в C++
C++ exceptions
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
HPX: C++11 runtime система для параллельных и распределённых вычислений
Ranges calendar-novosibirsk-2015-08
Использование maven для сборки больших модульных c++ проектов на примере Odin...
One definition rule - что это такое, и как с этим жить
DI в C++ тонкости и нюансы
Аскетичная разработка браузера
Concepts lite

Максим Хижинский Lock-free maps

  • 1. Concurrent mapS C++ Russia 2015Maxim Khizhinsky
  • 2. Lock-free hash tableLock-free hash table LIBCDS Максим Хижинский, C++ Russia 2015 0 1 2 3 4 5 6 X X X k1 k k k k k kk k k 2 3 4 5 6 7 8 9 T[8] Lock-free список коллизий 7 k 10
  • 3. Lock-free ordered listLock-free ordered list LIBCDS Максим Хижинский, C++ Russia 2015 Операции: ● insert( node ) ● erase( key ) ● find( key ) template <class T> struct node { std::atomic<node*> next_; T data_; }; H T52 8 Lock-free примитивы: ● atomic load/store ● atomic compare-and-swap (CAS)
  • 4. CAS — compare-and-swapCAS — compare-and-swap LIBCDS Максим Хижинский, C++ Russia 2015 template <typename T> bool CAS( T * pAtomic, T expected, T desired ) atomically { if ( *pAtomic == expected ) { *pAtomic = desired; return true; } else return false; };
  • 5. Lock-free list: insertLock-free list: insert LIBCDS Максим Хижинский, C++ Russia 2015 H T52 8 3 H T52 8 3 3. prev->next_.CAS( next, new_node ) 1. find insert position for key 3 2. new_node.next_.store( next ) H T52 8 prev next new_node
  • 6. Lock-free list: eraseLock-free list: erase LIBCDS Максим Хижинский, C++ Russia 2015 1. find key 3 2. prev->next_.CAS( found, next ) H T52 8 prev 3 found H T52 83 Проблема: параллельный insert next
  • 7. Lock-free list: insert/eraseLock-free list: insert/erase LIBCDS Максим Хижинский, C++ Russia 2015 A: find key 3 H T52 8 prev 3 found B: find insert pos for key 4 iprev inext A: erase key 3 H T52 83 prev->next_.CAS( found, next ) next B: insert key 4 H T52 83 4 iprev->next_.CAS( inext, new_item ) local vars
  • 8. Marked pointerMarked pointer LIBCDS Максим Хижинский, C++ Russia 2015 [ T.Harris, 2001 ] Двухфазное удаление: ● Логическое удаление — помечаем элемент ● Физическое удаление — исключаем элемент В качестве метки используем младший бит указателя
  • 9. Lock-free list: marked pointerLock-free list: marked pointer LIBCDS Максим Хижинский, C++ Russia 2015 H T52 8 prev 3 found iprev inext nextA: erase B: insert A: Logical deletion - mark item found H T52 83 found->next_.CAS( next, next | 1 ) B: iprev->next_.CAS( inext, new_item ) - failed!!! A: Physical deletion - remove item found H T52 83 prev->next_.CAS( found, next )
  • 10. Lock-free list: problemsLock-free list: problems LIBCDS Максим Хижинский, C++ Russia 2015 H T52 8 prev 3 found iprev inext nextA: erase B: insert iprev->next_.CAS( inext, new_item ) prev->next_.CAS( found, next ) local vars Вдруг уже удалены?..
  • 11. Lock-free list: problemsLock-free list: problems LIBCDS Максим Хижинский, C++ Russia 2015 Проблемы: ● Защита локальных данных — когда элемент можно безопасно удалить? ● ABA-проблема
  • 12. ABA-проблемаABA-проблема LIBCDS Максим Хижинский, C++ Russia 2015 52 prev 3 found next Thread A: erase(3) Thread B 52 3 erase(3); erase(5) 2 3 insert(4) Heap new node(4) alloc delete 42 preempted... 42 prev found next 5 addr(3) == addr(4) prev->next_.CAS( found, next ) - success!!! 2 мусор
  • 13. SMRSMR LIBCDS Максим Хижинский, C++ Russia 2015 Проблемы: ● Защита локальных данных — когда элемент можно безопасно удалить? ● ABA-проблема Решение: Safe memory reclamation (SMR) ● Tagged pointers ● Hazard Pointers ● User-space RCU
  • 14. Tagged pointersTagged pointers LIBCDS Максим Хижинский, C++ Russia 2015 pointer tag prev->next_.dwCAS( found, <next.ptr, prev->next_.tag + 1> ) template <class T> struct tagged_ptr { T * ptr; uintptr_t tag; }; Требует dwCAS — не везде есть Решает только ABA-проблему Освободить память нельзя, нужен free-list [ boost.lock-free ] H T52 8 prev 3 found next
  • 15. Tagged pointers: historyTagged pointers: history LIBCDS Максим Хижинский, C++ Russia 2015 ABA-проблема характерна только для CAS Архитектуры процессоров LL/SC: ● IBM PowerPC ● MIPS ● ARM ➢ LL — load linked ➢ SC — store conditional bool weak_CAS( T * ptr, T expected, T desired ) { T cur = LL( ptr ); return cur == expected && SC( ptr, desired ); } Эмуляция LL/SC на CAS — намного труднее CAS: ● x86, amd64 ● Sparc ● Itanium С++11 — только CAS
  • 16. Hazard pointersHazard pointers LIBCDS Максим Хижинский, C++ Russia 2015 ✔ Использует только атомарные чтение/запись  Защищает только локальные ссылки ✔ Размер массива отложенных (готовых к удалению) элементов ограничен сверху  Перед работой с указателем его следует объявить как hazard решает ABA-проблему Физическое удаление элементов
  • 17. Hazard pointersHazard pointers LIBCDS Максим Хижинский, C++ Russia 2015 H T52 8 prev 3 found next erase( Key k ) { hp_guard h1 = get_guard(); hp_guard h2 = get_guard(); retry: node * prev = Head; do { node * found = h2.protect( prev->next_); if ( found->key == k ) if (prev->next_.CAS( found, found->next_)) { hp_retire( found ); return true; } else goto retry; h1 = h2; prev = found; } while ( found->key < k ); return false; } Распределяем HP (TLS) Защищаем элемент Удаляем элемент
  • 18. Hazard pointersHazard pointers LIBCDS Максим Хижинский, C++ Russia 2015 P – thread count Thread 0 Thread HP Manager 0 1 … K - 1 HP[K] 0 1 2 … R - 1 Retired[R] Hazard Pointer Singleton Thread 1 Thread P - 1 K = 4 R = 2 KP <K,P, R> : R > K * P
  • 19. Hazard PointersHazard Pointers LIBCDS Максим Хижинский, C++ Russia 2015 Объявление Hazard Pointer'а – защита локальной ссылки class hp_guard { void * hp; // ... }; T * hp_guard::protect( std::atomic<T*>& what) { T * t; do { hp = t = what.load(); } while (t != what.load()); return t; } 0 1 … K - 1 HP[K]
  • 20. Hazard PointersHazard Pointers LIBCDS Максим Хижинский, C++ Russia 2015 Удаление элемента void hp_retire( T * what ) { push what to current_thread.Retired array if ( current_thread.Retired is full ) hp.Scan( current_thread ); } void hp::Scan() { void * guarded[K*P] = union HP[K] for all P thread; foreach ( p in current_thread.Retired[R] ) if ( p not in guarded[] ) delete p; } <K,P, R> : R > K * P 0 1 2 … R - 1 Retired[R] 0 1 … K - 1 HP[K]
  • 21. User-space Read-Copy UpdateUser-space Read-Copy Update LIBCDS Максим Хижинский, C++ Russia 2015 ✔ RCU — метод синхронизации: RCU.lock() / RCU.unlock() ✔ Разработан для почти-read-only данных (map, set) ✔ Очень легкие read-side lock ✔ Удаление элемента — ожидание окончания эпохи решает ABA-проблему Физическое удаление элементов RCU.lock(): ничего не блокирует Объявляет, что поток входит в текущую RCU-эпоху
  • 22. User-space RCUUser-space RCU LIBCDS Максим Хижинский, C++ Russia 2015 Map.find( ... ); Set.insert( ... ); Map.find( ... ); Map.erase( ... )... Thread 1 Set.find( ... ); Map.insert( ... ); Set.find( ... ); Set.insert( ... ); Thread N Эпоха 1 RCU.sync() - ждем, пока все потоки покинут эпоху 1 Set.find( ... ); Map.insert( ... ); Set.find( ... ); Set.insert( ... ); ... Map.erase; Map.find( ... ); Set.insert( ... ); Map.find( ... ); ++Эпоха Эпоха 2
  • 23. Lock-free hash tableLock-free hash table LIBCDS Максим Хижинский, C++ Russia 2015 0 1 2 3 4 5 6 X X X k1 k k k k k kk k k 2 3 4 5 6 7 8 9 T[8] Lock-free cписок: HP/RCU + marked pointers 7 k 10 Hash table + Lock-free ordered list No rehashing
  • 24. Split-ordered listSplit-ordered list LIBCDS Максим Хижинский, C++ Russia 2015 0 8 2 1 9 13 T[0] T[1] k iSentinel node Regular node N = 2 size() = 4 Load factor L: size() / N ≤ L Если L = 2, то вставка нового элемента приводит к увеличению hash table Hash table Lock-free ordered list
  • 25. Skip listSkip list LIBCDS Максим Хижинский, C++ Russia 2015 X X X X X X X X10 15 23 34 5542 23 Tower h = 3 Вероятностная структура данных: P[ h == 1 ] = 1/2 P[ h == k ] = 1/2 k , 0 < k < 32 h = lsb( rand() ) O(log(N))
  • 26. PerformancePerformance LIBCDS Максим Хижинский, C++ Russia 2015 Intel Dual Xeon X5670 2.93 GHz 12 cores 24 threads / 24 GB RAM
  • 27. Concurrent mapsConcurrent maps Максим Хижинский, C++ Russia 2015 Спасибо за внимание! libcds.dev@gmail.com https://github.com/khizmax/libcds