Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Алексей Фёдоров — Общество Мертвых Потоков

Moscow JUG
September 24, 2015

Алексей Фёдоров — Общество Мертвых Потоков

Как шутят эксперты по многопоточности, программисты делятся на два типа: те, кто ничего не знает о многопоточности и те, кто думают, что что-то знают ☺ В этом докладе мы поговорим про дедлоки и способы борьбы с ними, включающие решения на Atomic/CAS.
В первой части мы поговорим о проблеме Обедающих Философов, классической многопоточной задаче, и на ее примере посмотрим, что такое Deadlock и Starvation. Сначала будет описана сама задача, потом будет дан небольшой кусок теории, после чего будет показано несколько различных вариантов ее решения на Java, каждое из которых вскроет новые многопоточные грабли.

Во второй части речь пойдет о lock-free алгоритмах и структурах данных, посмотрим, какие стандартные средства нам для этого предоставляет Java. Мы поговорим о CAS-операциях, Atomic-типах, неблокирующих алгоритмах и проблеме ABA.

Moscow JUG

September 24, 2015
Tweet

More Decks by Moscow JUG

Other Decks in Programming

Transcript

  1. 3 Чего  не  будет  в  презентации • Определений  из  учебника

    - Больше  интересует  сама  концепция • Сравнения  производительности • Советов,  как  правильно  писать  код • Холиваров* • Серебряных  пуль,  волшебных  фреймворков и  т.п. *  Нет,  ну  если  кто-­‐то  очень  захочет,  то  можно,  конечно…
  2. 4 А  что  будет-­то? • Пара  простых  многопоточных  примеров •

    Куча  связанных  с  ними  проблем • Варианты  решений - Которые,  разумеется,  не  работают - Ну  некоторые  работают - Иногда - Наверное…
  3. 5 Пререквизиты Нужно  примерно понимать,  что  такое • Thread •

    Runnable • synchonized • Lock lock = new ReentrantLock(false) • volatile • AtomicInteger • Compare-And-Set
  4. 6 Стенд • Apple  MacBook  Pro  Retina,  2014 - Intel

     Core  i7 - 4  cores  x  2  threads  =  8  HW  threads - 2,3  GHz - 16  Gb  RAM - Oracle  JDK  8  update  60 • Mac  OS  X  10.10.5
  5. 8 • 5  философов  по  кругу – Тарелка  с  едой

     перед  каждым – Вилки  между  тарелками • Каждый  может – Размышлять – Брать  соседнюю  вилку – Есть  (строго  двумя  вилками!) – Класть  одну  вилку Задача  о  философах
  6. 9 Проблемы  с  обедающими  философами Пусть  каждый  философ  действует  по

      некоторому  алгоритму • Могут  ли  все  философы  умереть  с   голоду? • Можно  ли  составить  такой   алгоритм,  чтобы  все  философы   гарантированно не  умерли  с   голоду?
  7. 10 Параметры  задачи • Количество  философов • Есть  ли  возможность

     положить  вилку,  не  пожрамши • Сколько  времени  философ  ест - Фиксированное  или  случайная  величина • Сколько  времени  философ  размышляет - Фиксированное  или  случайная  величина - Как  это  время  соотносится  с  временем  еды • Какие  ещё  инструменты/элементы  есть  в  системе? • Что  ещё?
  8. 11 Фиксированное  время  и  случайное  время • Случайное  время  задаётся

     какой-­‐то  функцией   распределения • Константа  тоже задаётся  функцией  распределения - (А  бывают  ли  вообще  константы  в  реальном  мире?)
  9. 12 Фиксированное  время  и  случайное  время • Случайное  время  задаётся

     какой-­‐то  функцией   распределения • Константа  тоже задаётся  функцией  распределения - (А  бывают  ли  вообще  константы  в  реальном  мире?)
  10. 16 Простое  решение • Когда  философ  хочет  есть,  он  делает

     следующие  шаги: 1. Берёт  левую  от  себя  вилку  («сено») 2. Берёт  правую  от  себя  вилку  («солома») 3. Ест 4. Кладёт  одну  вилку 5. Кладёт  другую  вилку 6. Размышляет • И  так  по  кругу
  11. 19

  12. 21 Ресурсы  и  взаимоблокировка Ресурс – объект,  к  которому  предоставляется

     доступ Во  время  работы  процесс  может  брать  (захватывать)   ресурсы
  13. 22 Взаимоблокировка  (Deadlock) Взаимоблокировка – такое  состояние  системы,   при

     котором  два  или  более  процессов  не  могут   продолжать  своё  выполнение  из-­‐за  отсутствия   необходимых  для  этого  ресурсов. Каждый  ждёт  другого,  поэтому  никто  не  может   продолжить
  14. 23 Выгружаемые  и  невыгружаемые  ресурсы • Выгружаемые  ресурсы  — ресурсы,

     которые  могут быть   безболезненно  отобраны  у  процесса,  который  ими  обладает • Невыгружаемые  ресурсы  — ресурсы,  которые  нельзя отобрать  у  процесса,  не  вызвав  при  этом  сбой  в  вычислениях • Мы  будем  говорить,  в  основном,  о  невыгружаемых  ресурсах
  15. 24 Операции  над  невыгружаемыми  ресурсами • Запрос  ресурса - Берём

    ресурс   - или  ждём (встаём  в  «очередь»  ожидания) • Использование  ресурса • Освобождение  ресурса
  16. 26 Условия  возникновения  взаимоблокировок Коффман,  1971 1. Условие  взаимного  исключения

    2. Условие  удержания  и  ожидания 3. Условие  невыгружаемости 4. Условие  циклического  ожидания
  17. 27 Условие  взаимного  исключения Каждый  ресурс  либо  выделен  в  данный

     момент только   одному процессу,  либо  доступен для  всех.
  18. 28 Условие  удержания  и  ожидания Процессы,  удерживающие  в  данный  момент

     ранее   выделенные  им  ресурсы,  могут запрашивать  новые   ресурсы.
  19. 29 Условие  невыгружаемости Ранее  выделенные  ресурсы  не  могут  быть  принудительно

      отобраны у  процесса.   Они  должны  быть  явным  образом  высвобождены  тем   процессом,  который  их  удерживает.
  20. 30 Условие  циклического  ожидания Должна  существовать  кольцевая  последовательность  из  

    двух  и  более  процессов,  каждый  из  которых  ожидает   высвобождения  ресурса,  удерживаемого  следующим   членом  последовательности.
  21. 34 Условия  возникновения  взаимоблокировок  — ещё  раз Коффман,  1971 1.

    Условие  взаимного  исключения 2. Условие  удержания  и  ожидания 3. Условие  невыгружаемости 4. Условие  циклического  ожидания
  22. 37 Стратегии  борьбы  с  блокировками • Игнорирование  проблемы • Обнаружение

     и  восстановление • Динамическое  уклонение • Предотвращение  за  счёт  подавления  любого  из   четырёх  условий  Коффмана
  23. 38 Кто  использует  стратегии  борьбы? • Базы  данных - Блокировки

     на  строках,  таблицах,  индексах  и  т.д.
  24. 39 Кто  использует  стратегии  борьбы? • Базы  данных - Блокировки

     на  строках,  таблицах,  индексах  и  т.д. • JVM
  25. 40 Кто  использует  стратегии  борьбы? • Базы  данных - Блокировки

     на  строках,  таблицах,  индексах  и  т.д. • JVM - А  вот  и  нет! - Ручками,  ручками! - Ну  и  головой…
  26. 41 Алгоритм  Страуса (Делаем  вид,  что  проблема  отсутствует) • Насколько

     часто  возникает  проблема? • Как  часто  возникают  сбои  в  системе  по   другим  причинам? • Насколько  серьёзны  могут  быть   последствия?
  27. 42 Обнаружение  взаимоблокировок  и   восстановление  работоспособности • Шаги -

    Позволить  блокировке  произойти - Пытаться  обнаружить  момент  возникновения - Попробовать  восстановить  работоспособность В  нашем  примере  можно  просто  перезапускать  философов
  28. 43 Выход  из  взаимоблокировки • Приоритетный  захват  ресурсов - Приоритезировать

    (все)  процессы - Отобрать  ресурс  у  менее  приоритетного  процесса • Откат  (см.  след.  слайд) • Уничтожение  и  перезапуск  процессов
  29. 44 Выход  из  взаимоблокировки  — Откат • Периодически  создаются  контрольные

     точки • При  обнаружении  блокировки  происходит  откат - При  откате  часть  работы  (которая  была  выполнена   после  прохождения  последней  контрольной  точки)   теряется
  30. 48 Предотвращение  взаимоблокировки • Атака  условия  взаимного  исключения • Атака

     условия  ожидания  и  удержания • Атака  условия  циклического  ожидания • Атака  условия  невыгружаемости
  31. 49 Атака  условия  взаимного  исключения • Возможна  редко  — часто

     программа  становится   некорректной • Идея  — убирать  ненужные  блокировки - Делать  нужно  осторожно,  чтобы  функциональность   не  страдала - Заменять  на  другие  механизмы
  32. 50 Атака  условия  ожидания  и  удержания • Запрашивать  ВСЕ  необходимые

     ресурсы  не  в   процессе  работы,  а  до  начала  работы.   - Но  не  всегда  ресурсы  известны  заранее • Вначале  временно  высвободить  все  удерживаемые   ресурсы
  33. 52 Атака  условия  циклического  ожидания • Нумерация  ресурсов! - Захватывать

     ресурсы  только  в  порядке   возрастания  номеров 1 2 3 4 5 1 2 3 4 5
  34. 54 Голодание    (Starvation) • Голодание — ситуация,  в  которой

     поток,  от  которого   ожидается  прогресс,  (практически)  стоит  на  месте.
  35. 55 Голодание    (Starvation) • Голодание — ситуация,  в  которой

     поток,  от  которого   ожидается  прогресс,  (практически)  стоит  на  месте. • Заблуждение - Голодание  может  осуществиться,  только  если  потоки   с  более  высоким  приоритетом  постоянно  берут   ресурсы,  которые  нужны  голодающему  потоку
  36. 59

  37. 60 Что  же  делать • Решение  с  посредником: официант  решает,

     кому   можно  брать  вилку,  а  кому  нет - Решение  с  общим  критическим  ресурсом - Решение  с  семафором
  38. 62 И  все-­таки  бенчмарки… 5  потоков  по  2 секунды eat

    think Ordered   Locks Common   Unfair  Lock Common  Fair   Lock Semaphore 0ms 0ms 25 000 000 55 000 000 450 000 11 000 000 0ms 1ms 7 900 7 700 7 500 4 000 1ms 0ms 1 600 1 500 1 500 1 700 1ms 1ms 3 100 1 500 1 500 2 700
  39. 66

  40. 68 Модели • Модель  с  разделяемой  памятью - Регистры -

    Операции:  read,  write - Удобно  программировать,  все  привыкли • Модель  с  передачей  сообщений - Послать  сообщение - Похожа  на  то,  как  реально  работает  железо
  41. 71 Параллелизм  — ОС - Слушать  музыку  и  переписываться в

     фейсбуке в  Одноклассниках - При  зависании  одной  программы  другие   продолжают  работать - и  т.п.
  42. 72 Преимущества  параллелизма • Использование  нескольких  ядер/процессоров - Да  и

     на  1  ядре  тоже!  (async I/O) • Простота  моделирования - Абстракция:  фреймворк забирает  сложность • Упрощенная  обработка  асинхронных  событий • Более  отзывчивые  интерфейсы  пользователя - Event  Dispatch  Thread  (EDT),  async calls
  43. 73 Параллелизм  на  уровне  отдельно  взятой  программы • Эффективное  использование

     ресурсов • Удобство,  простота  написания  кода • Справедливость   - Обработка  запросов  пользователей  на  серверах   соцсети с  одинаковым  приоритетом - Читатели  и  писатели - Fairness  (честность)
  44. 77 Блокировки • java.util.concurrent— since  Java  5 - Lock —>

    ReentrantLock - ReadWriteLock —> ReentrantReadWriteLock - StampedLock — since Java 8 • Synchronized  method  /  section • wait() / notify() / notifyAll()
  45. 78 Блокировки • java.util.concurrent— since  Java  5 - Lock —>

    ReentrantLock - ReadWriteLock —> ReentrantReadWriteLock - StampedLock — since Java 8 • Synchronized  method  /  section • wait() / notify() / notifyAll() Общее: ожидание
  46. 79 Проблемы  блокировок • Взаимоблокировки  (Deadlocks) • Инверсия  приоритетов •

    Надежность  — вдруг  владелец  блокировки  помрет? • Performance - Параллелизма  в  критической  секции  нет! - Владелец  блокировки  может  быть  вытеснен   планировщиком
  47. 80 Закон  Амдала • α — часть общего объема вычислений,

    которую нельзя распараллелить • 1-α — часть, которую можно распараллелить • p — количество потоков
  48. 81 Закон  Амдала • α — часть общего объема вычислений,

    которую нельзя распараллелить • 1-α — часть, которую можно распараллелить • p — количество потоков
  49. 83 Классификация • Без  препятствий  (Obstruction-­‐Free)  — поток  совершает  

    прогресс,  если  не  встречает  препятствий  со  стороны   других  потоков • Без  блокировок  (Lock-­‐Free) — гарантируется  системный   прогресс  хотя  бы  одного  потока • Без  ожидания (Wait-­‐Free) — каждая  операция   выполняется  за  фиксированное  число  шагов,  не   зависящее  от  других  потоков
  50. 84 Консенсус • Объект  consensus  с  операцией  decide(v): - consensus.decide(v)

     ≠  const - wait-­‐free • N  Потоков  вызывают  consensus.decide() - i-­‐ый поток  вызывает  consensus.decide(vi ) - Каждый  поток  вызывает  не  более  1  раза - decide() возвращает  одно  из  vi • decide()  — протокол  консенсуса
  51. 85 Консенсусное число • Мощность  консенсуса  — максимальное  количество  

    (N) потоков,  для  которых  данный  объект   обеспечивает  консенсус • Консенсусное число  примитива  синхронизации  — максимальная  мощность  консенсуса,  который  можно   построить  на  базе  данного  примитива и  некоторого   количества  атомарных  регистров - То  есть,  существует  реализация  метода  decide  для   N  потоков,  использующая  данный  примитив  как   строительный  блок
  52. 86 Консенсусные числа  различных  операций • Операции  на  регистрах  —

    1 • Read-­‐Modification-­‐Write  (RMW) — 2 - Common2  Class — коммутируют  друг  с  другом  или   перезаписывают  друг  друга - Универсальные  операции  — ∞ - Сравнение  с  обменом  (CAS):   Compare-­‐And-­‐Swap,  Compare-­‐And-­‐Set
  53. 87 Compare  and  Swap • Compare-and-swap (CAS) - IA32, x64

    - SPARC • load-linked / store-conditional (LL/SC) - PowerPC - ARM
  54. 89 CAS  Loop  — типичный  паттерн  применения 1. Прочитать  значение

     A  из  переменной  V 2. Взять  какое-­‐то  новое  значение  B  для  V 3. Использовать  CAS  для  атомарного  изменения  V  из  A   в  B до  тех  пор,  пока  другие  потоки  меняют  значение   V  во  время  этого  процесса Атомарность Read-­‐Modify-­‐Write  реализуется  за  счет   постоянного  мониторинга системы  на  предмет   постороннего  вмешательства
  55. 91 Fast  vs.  slow  path • Каждый  блок  кода  может

     иметь,  как  минимум,  два   пути  исполнения:  короткий  и  длинный • Lock:  contended  vs.  Uncontended • Uncontended  Lock: - ≥  1  CAS
  56. 92 Недостатки  CAS • CAS  заставляет  потоки,  которые  его  вызывают,

      работать  в  условиях  соревнования  (contention) - Больше  contention  =  больше  бесполезных  циклов   процессора,  трата  процессорного  времени • Написание  корректных  и  быстрых  алгоритмов  на     CAS  требует  специальной  подготовки
  57. 94 Поддержка  CAS  в  Java • В  Java  5  появился

     JSR166 - пакет  java.util.concurrent - пакет  java.util.concurrent.atomic • На  платформах,  поддерживающих  CAS,  JIT-­‐ компилятор  делает  inline  соответствующих   машинных  инструкций • Load  Linked  /  Store  Conditional  
  58. 95 Atomic  variable  classes • Scalars • Field  updaters •

    Arrays • Compound  variables • Accumulators - since  Java  8
  59. 97 AtomicInteger • boolean compareAndSet(int expect, int update) • int

    addAndGet(int delta) • int getAndDecrement() • int getAndIncrement() • int incrementAndGet() • …
  60. 98 AtomicInteger • boolean compareAndSet(int expect, int update) • int

    addAndGet(int delta) • int getAndDecrement() • int getAndIncrement() • int incrementAndGet() • … Эти  операции  — блокирующие?
  61. 101 Field  Updaters • AtomicIntegerFieldUpdater - Reflection-­‐based  updater  for  volatile

     int • AtomicLongFieldUpdater - Reflection-­‐based  updater  for  volatile  long • AtomicReferenceFieldUpdater - Reflection-­‐based  updater  for  volatile  object
  62. 102 AtomicLongFieldUpdater - long  addAndGet(T  obj,  long  delta) - boolean

    compareAndSet(T  obj,  long  expect,   long   update) - long  getAndAdd(T  obj,  long  delta) - long  incrementAndGet(T  obj)
  63. 106 AtomicLongArray • long addAndGet(int i, long delta) • long

    getAndAdd(int i, long delta) • boolean compareAndSet(int i, long expect, long update) • long incrementAndGet(int i) • …
  64. 107 Compound  Variables • AtomicMarkableReference - compareAndSet( V expectedReference, V

    newReference, boolean expectedMark, boolean newMark) • AtomicStampedReference - boolean compareAndSet( V expectedReference, V newReference, int expectedStamp, int newStamp)
  65. 110 • Алгоритм  называется  неблокирующим  (nonblocking),  если   отказ  или

     остановка  любого  потока  не  может  привести  к   отказу  или  остановке  любого  другого  потока • Алгоритм  называется  свободным  от  блокировок(lock-­‐free),   если  на  каждом  шаге  какой-­‐то  поток  выполняет  работу   (make  progress) • nonblocking и  lock-­‐free  — это  разные  вещи! - Алгоритмы  на  CAS  могут быть  одновременно   неблокирующими  и  свободными  от  блокировок   110 Неблокирующие  алгоритмы
  66. 116

  67. 117

  68. 118