Top Banner
Алексей Федоров, Одноклассники Синхронизация без блокировок и СМС
86

Алексей Федоров

Apr 13, 2017

Download

Software

CodeFest
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Алексей Федоров

АлексейФедоров,Одноклассники

Синхронизация без блокировок и СМС

Page 2: Алексей Федоров

Зачем вы здесь?

Page 3: Алексей Федоров

3

Page 4: Алексей Федоров

4Concurrency

Page 5: Алексей Федоров

5Concurrency

Page 6: Алексей Федоров

6 Много интересных докладов в других залах

Page 7: Алексей Федоров

7

Новичкам в области многопоточности

SorryПерейдите в другой зал

Page 8: Алексей Федоров

8

Новичкам в области многопоточности

SorryПерейдите в другой зал

Новичкам в неблокирующей синхронизации

Короткое введение

Page 9: Алексей Федоров

9

Новичкам в области многопоточности

SorryПерейдите в другой зал

Новичкам в неблокирующей синхронизации

Короткое введение

Продвинутым многопоточным программистам

Поговорим о деталях реализации CAS/atomics!

Page 10: Алексей Федоров

10

Новичкам в области многопоточности

SorryПерейдите в другой зал

Новичкам в неблокирующей синхронизации

Короткое введение

Продвинутым многопоточным программистам

Поговорим о деталях реализации CAS/atomics!

Хипстерам Поговорим про хайп!Immutable vs. Mutable

Page 11: Алексей Федоров

11Модели

• Модельсразделяемойпамятью- Операциинаатомарныхрегистрах:read,write- Удобнопрограммировать,всепривыкли

• Модельспередачейсообщений- Операции:send,onReceive- Похожанато,какреальноработаетжелезо

Page 12: Алексей Федоров

12Терминология

• Нетустоявшейсятерминологии

• Термины:- Parallel- Concurrent- Distributed

Page 13: Алексей Федоров

13Виды параллелизма

• Науровнеоперационнойсистемы

• Науровнеоднойпрограммы/процесса

Page 14: Алексей Федоров

14Параллелизм — ОС

• СлушатьмузыкуипереписыватьсявфейсбукевОдноклассниках

• Призависанииоднойпрограммыдругиепродолжаютработать

• ит.п.

Page 15: Алексей Федоров

15Преимущества параллелизма

• Использованиенескольких ядер/процессоров- Даина1ядретоже!(async I/O)

• Простота моделирования- Абстракция:фреймворк забираетсложность

• Упрощеннаяобработкаасинхронных событий• Болееотзывчивые интерфейсыпользователя- EventDispatchThread(EDT),async calls

Page 16: Алексей Федоров

16Параллелизм на уровне отдельно взятой программы

• Эффективное использованиересурсов• Удобство,простота написаниякода• Справедливость- Обработказапросовпользователейнасерверахсоцсети содинаковымприоритетом

- Читателииписатели

- Fairness(честность)

Page 17: Алексей Федоров

17

Lock lock = new ReentrantLock(true);

Page 18: Алексей Федоров

18Честность!

Lock lock = new ReentrantLock(true);

Page 19: Алексей Федоров

19 Блокировки

Old Schoolwait()notify()notifyAll()

synchronized {doSomething();

}

public synchronized foo() {doSomethingElse();

}

Вязыке

Page 20: Алексей Федоров

20 Блокировки

Old Schoolwait()notify()notifyAll()

synchronized {doSomething();

}

public synchronized foo() {doSomethingElse();

}Lock lock = new ReentrantLock();try {

lock.lock();doSomething();

} finally {lock.unlock();

}

Вязыке Вбиблиотеке(JDK)

java.util.concurrent.*java.util.concurrent.atomic.*

Page 21: Алексей Федоров

21Counter

public interface Counter {

long get();

void increment();

}

Page 22: Алексей Федоров

22Simple Counter

public class SimpleCounter implements Counter {

long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

Page 23: Алексей Федоров

23Volatile Counter

public class VolatileCounter implements Counter {

volatile long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

Page 24: Алексей Федоров

24 Synchronized Counter

public class SynchronizedCounter implements Counter {

long value = 0;

public synchronized long get() {return value;

}

public synchronized void increment() {value++;

}

}

Page 25: Алексей Федоров

25 Проблемы блокировок

• Взаимоблокировки (Deadlocks)

Page 26: Алексей Федоров

26 Проблемы блокировок

• Взаимоблокировки (Deadlocks)

• Инверсия приоритетов

Page 27: Алексей Федоров

27 Проблемы блокировок

• Взаимоблокировки (Deadlocks)

• Инверсия приоритетов

• Надежность — вдруг владелец блокировки помрет?

Page 28: Алексей Федоров

28 Проблемы блокировок

• Взаимоблокировки (Deadlocks)

• Инверсия приоритетов

• Надежность — вдруг владелец блокировки помрет?

• Performance– Параллелизма в критической секции нет!– Владелец блокировки может быть вытеснен планировщиком

Page 29: Алексей Федоров

29ЗаконАмдала

α часть общего объема вычислений, которую нельзя распараллелить

1-α часть, которую можно распараллелить

p количество потоков

Page 30: Алексей Федоров

30ЗаконАмдала

Sp=𝟏

α#𝟏%α𝐩

α часть общего объема вычислений, которую нельзя распараллелить

1-α часть, которую можно распараллелить

p количество потоков

Page 31: Алексей Федоров

Нам нужно что-то другое

Page 32: Алексей Федоров

Добро пожаловать в неблокирующую синхронизацию!

Page 33: Алексей Федоров

33If-Modify-Write

volatile int value = 0;

if (value == 0) {value = 42;

}

NoAtomicityintermsofJMM

Page 34: Алексей Федоров

34Compare and Swap

int value = 0;

synchronized (...) {if (value == 0) {

value = 42;}

}

Page 35: Алексей Федоров

35Введем волшебную операцию

int value = 0;

i.compareAndSet(0, 42);

Page 36: Алексей Федоров

36CompareandSwap— HardwareSupport

compare-and-swapCAS

load-link / store-conditionalLL/SC

cmpxchg

ldrex/strex lwarx/stwcx

Page 37: Алексей Федоров

37 CAS Semanticspublic class PseudoCAS {

private long value;

public synchronized long get() { return value; }

public synchronized long compareAndSwap(long expected, long newV) {long oldValue = value;if (oldValue == expected) {

value = newV;}return oldValue;

}

public synchronized boolean compareAndSet(long expected, long newV){return expected == compareAndSwap(expected, newV);

}}

Page 38: Алексей Федоров

38 Pseudo-CAS Counter

public class PseudoCasLoopCounter implements Counter {

private PseudoCAS value = new PseudoCAS();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}}

Page 39: Алексей Федоров

39 Pseudo-CAS Counter

public class PseudoCasLoopCounter implements Counter {

private PseudoCAS value = new PseudoCAS();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}}

Page 40: Алексей Федоров

CAS in Java

Page 41: Алексей Федоров

41CAS in Java

Since Java 5, JSR166

java.util.concurrent.atomic

• Scalars• Field updaters• Arrays• Compound variables• Accumulators/Adders

since Java 8

Page 42: Алексей Федоров

42Scalars

• AtomicBoolean

• AtomicInteger

• AtomicLong

• AtomicReference

Page 43: Алексей Федоров

43Scalars

• AtomicBoolean

• AtomicInteger

• AtomicLong

• AtomicReference

Page 44: Алексей Федоров

44

• boolean compareAndSet(long expect, long update)

• long addAndGet(long delta)

• long getAndAdd(long delta)• long getAndDecrement()• long getAndIncrement()• long incrementAndGet()• …

AtomicLong

Page 45: Алексей Федоров

45

• boolean compareAndSet(long expect, long update)

• long addAndGet(long delta)

• long getAndAdd(long delta)• long getAndDecrement()• long getAndIncrement()• long incrementAndGet()• …

AtomicLong

Page 46: Алексей Федоров

46 CAS Counter

public class CasLoopCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Page 47: Алексей Федоров

47 Недостатки CAS

Contended CAS —> tons of useless CPU cycles

do {v = value.get();

} while (value.compareAndSet(v, v + 1));

Написание быстрых и корректных алгоритмов на CAS требует экспертизы

Page 48: Алексей Федоров

48AtomicLong

• boolean compareAndSet(long expect, long update)

• long addAndGet(long delta)

• long getAndAdd(long delta)• long getAndDecrement()• long getAndIncrement()• long incrementAndGet()• …

Page 49: Алексей Федоров

49Get-and-Add Counter

public class CasLoopCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {value.getAndAdd(1);

}

}

Page 50: Алексей Федоров

50atomicLong.getAndAdd(5)

JDK7u95 JDK8u72

60

9 7 6

100

27 27 27

1 2 3 4

ops/μs

threads

Page 51: Алексей Федоров

51atomicLong.getAndAdd(5)

JDK7u95 JDK8u72

60

9 7 6

100

27 27 27

1 2 3 4

ops/μs

threads

Page 52: Алексей Федоров

52atomicLong.getAndAdd(5)

JDK7u95 JDK8u72

60

9 7 6

100

27 27 27

1 2 3 4

ops/μs

threads

Page 53: Алексей Федоров

53

loop:mov 0x10(%rbx),%raxmov %rax,%r11add $0x5,%r11lock cmpxchg %r11,0x10(%rbx)sete %r11bmovzbl %r11b,%r11dtest %r10d,%r10dje loop

JDK7u95-XX:+PrintAssembly

atomicLong.getAndAdd(5)

Page 54: Алексей Федоров

54

lock addq $0x5,0x10(%rbp))loop:mov 0x10(%rbx),%raxmov %rax,%r11add $0x5,%r11lock cmpxchg %r11,0x10(%rbx)sete %r11bmovzbl %r11b,%r11dtest %r10d,%r10dje loop

JDK7u95-XX:+PrintAssembly JDK8u77-XX:+PrintAssembly

atomicLong.getAndAdd(5)

JDK7u95 JDK8u72

60

9 7 6

100

27 27 27

1 2 3 4

ops/μs

threads

Page 55: Алексей Федоров

55 AtomicLong.getAndAdd()— JDK7

Page 56: Алексей Федоров

56 AtomicLong.getAndAdd()— JDK7

cmpxchg

Page 57: Алексей Федоров

57 AtomicLong.getAndAdd()— JDK8

Page 58: Алексей Федоров

58 AtomicLong.getAndAdd()— JDK8

lock addqJVMIntrinsic

Page 59: Алексей Федоров

59

counterType Cnt Score Error UnitsLONG 5 211.247 ± 7.532 ops/usVOLATILE_LONG 5 24.837 ± 1.664 ops/usALFU 5 27.272 ± 1.946 ops/usSYNCHRONIZED 5 10.231 ± 0.592 ops/usUNFAIR_LOCK 5 19.959 ± 4.268 ops/usFAIR_LOCK 5 0.225 ± 0.009 ops/usCAS_LOOP 5 6.125 ± 0.225 ops/usADD_AND_GET 5 26.701 ± 0.620 ops/us

Бенчмарки!

Thanks to Nitsan Wakarthttp://psy-lob-saw.blogspot.ru/2014/06/jdk8-update-on-scalable-counters.html

Core(TM) i7-47704 x 2 x 1.9 Ghz(downgraded)

Ubuntu 14.04.33.13.0-83-genericx86_64taskset -c 0,1,2,3(thread affinity)

Page 60: Алексей Федоров

60Multivariable Invariant

Page 61: Алексей Федоров

61 Multivariable Invariant

Page 62: Алексей Федоров

62 Field Updaters

• AtomicIntegerFieldUpdater

– Reflection-based updater for volatile int

• AtomicLongFieldUpdater

– Reflection-based updater for volatile long

• AtomicReferenceFieldUpdater

– Reflection-based updater for volatile object

Page 63: Алексей Федоров

63AtomicLongFieldUpdater

long addAndGet(T obj, long delta)

boolean compareAndSet(T obj, long exp, long upd)

long getAndAdd(T obj, long delta)

long incrementAndGet(T obj)

Page 64: Алексей Федоров

64VolatileCounter

public class VolatileCounter implements Counter {

volatile long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

Page 65: Алексей Федоров

65VolatileCounter

public class VolatileCounter implements Counter {

volatile long value = 0;

public long get() {return value;

}

public void increment() {value++;

}

}

Page 66: Алексей Федоров

66 AtomicLongFieldUpdater-based Counterprivate final VolatileCounter counter = new VolatileCounter();

ALFU<VolatileCounter> updater= ALFU.newUpdater(VolatileCounter.class, "value");

public AFUCounter() throws NoSuchFieldException {Field field = VolatileCounter.class.getDeclaredField("value");field.setAccessible(true);

}

public long get() { return updater.get(counter);

}

public void increment() { updater.addAndGet(counter, 1);

}

Page 67: Алексей Федоров

67AtomicLongFieldUpdater

Page 68: Алексей Федоров

68AtomicLongFieldUpdater

Page 69: Алексей Федоров

69AtomicArrays

AtomicIntegerArray

AtomicLongArray

AtomicReferenceArray

long addAndGet(int i, long delta)

long getAndAdd(int i, long delta)

boolean compareAndSet(int i, long exp, long upd)

long incrementAndGet(int i)

Page 70: Алексей Федоров

70 Compound Variables

AtomicMarkableReference V сompareAndSet (V expectedRef, V newRef, boolean expectedMark, boolean newMark

)

AtomicStampedReference boolean compareAndSet (V expectedRef, V newRef, int expectedStamp, int newStamp

)

Page 71: Алексей Федоров

71 Accumulators

• DoubleAccumulator

• DoubleAdder

• LongAccumulator

• LongAdder

• (Striped64)

• void accumulate(long x)

• long get()

• long getThenReset()

• void reset()

Page 72: Алексей Федоров

72Non-blocking Guarantees

Wait-Freeбез ожидания

Per-thread progress is guaranteed

Lock-Freeбез блокировок

Overall progress is guaranteed

Obstruction-Freeбез препятствий

Per-thread progress is guaranteedif thread has been isolated (with all obstructing threads suspended)

Page 73: Алексей Федоров

73 AtomicLong-based Counter

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguarantees?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 74: Алексей Федоров

74 AtomicLong-based Counter

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguarantees?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 75: Алексей Федоров

75 AtomicLong-based Counter

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguaranteesonx64?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 76: Алексей Федоров

76 AtomicLong-based Counter

public class CasCounter implements Counter {

private AtomicLong value = new AtomicLong();

public long get() {return value.get();

}

public void increment() {long v;do {

v = value.get();} while (value.compareAndSet(v, v + 1));

}

}

Anyguaranteesonx64?A. Wait-FreeB. Lock-FreeC. Obstruction-FreeD. Noguarantees

Page 77: Алексей Федоров

CAS в .NET

Page 78: Алексей Федоров

78Interlocked

Page 79: Алексей Федоров

79Interlocked

Page 80: Алексей Федоров

Неблокирующиеструктурыданных

Page 81: Алексей Федоров

81Неблокирующий

стек

Page 82: Алексей Федоров

82

Michael and Scott, 1996https://www.research.ibm.com/people/m/michael/podc-1996.pdf

Потоки помогают друг другу

Неблокирующаяочередь

Page 83: Алексей Федоров

Материалы

Page 84: Алексей Федоров

84Литература

Page 85: Алексей Федоров

85Материалы

• Все-все-все— bit.ly/concurrency-interest• Nitsan Wakart — psy-lob-saw.blogspot.com• АлексейШипилёв — shipilev.net• АндрейАкиньшин— aakinshin.net/ru/blog/

Page 86: Алексей Федоров

Вопросыиответы