ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное...

226
Лекция 7. Атомарные операции. Внеочередное выполнение инструкций. Барьеры памяти. Семантика захвата- освобождения. Модель памяти C++ Пазников Алексей Александрович Кафедра вычислительных систем СибГУТИ Сайт курса: http://cpct.sibsutis.ru/~apaznikov/teaching/ Вопросы: https://piazza.com/sibsutis.ru/fall2014/pct14/home Параллельные вычислительные технологии Осень 2014 (Parallel Computing Technologies, PCT 14)

Upload: alexey-paznikov

Post on 23-Jul-2015

133 views

Category:

Education


0 download

TRANSCRIPT

Page 1: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Лекция 7. Атомарные операции. Внеочередное выполнение инструкций. Барьеры памяти. Семантика захвата-освобождения. Модель памяти C++

Пазников Алексей АлександровичКафедра вычислительных систем СибГУТИ

Сайт курса: http://cpct.sibsutis.ru/~apaznikov/teaching/Вопросы: https://piazza.com/sibsutis.ru/fall2014/pct14/home

Параллельные вычислительные технологииОсень 2014 (Parallel Computing Technologies, PCT 14)

Page 2: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарные переменные

2

Page 3: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарные операции

▪ Операция над разделяемой переменной атомарная, если она выполняется потоком за один неделимый шаг. Ни один из других потоков не может обнаружить эту переменную в промежуточном состоянии.

▪ Если операции, которые совершают потоки над раздялемыми переменными, не атомарны, то это приведёт к гонкам данных.

▪ Гонки данных являются причиной неопредлённого поведения, поскольку они приводят к частичным (фрагментированным, “разорванным”) чтениям и записям переменных.

3

Page 4: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Фрагментированные чтения и записи

uint64_t shared;

int main() {

shared = 0x100000002;

...

4

Page 5: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Фрагментированные чтения и записи

mov DWORD PTR shared, 2

mov DWORD PTR shared+4, 1

uint64_t shared;

int main() {

shared = 0x100000002;

...

gcc -m32 -S -masm=intel -O1 prog.c

запись младших 32 битзапись старших 32 бит

▪ Выполнение присваивания 64-битного целого shared = 42 на 32-разрядной архитектуре выполняется за 2 инструкции.

▪ Операция записи не атомарная.5

Page 6: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Фрагментированные чтения и записи

mov DWORD PTR shared, 2

mov DWORD PTR shared+4, 1

uint64_t shared;

int main() {

shared = 0x100000002;

...

gcc -m32 -S -masm=intel -O1 prog.c

1 потокзапись старших 32 бит

▪ Вытеснение потока после записи младших бит приведёт к тому, что эти биты останутся в памяти и будут использованы другими потоками.

▪ На многоядерных системах даже не требуется вытеснения. 6

Page 7: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Фрагментированные чтения и записи

mov DWORD PTR shared, 2

mov DWORD PTR shared+4, 1

uint64_t shared;

int main() {

shared = 0x100000002;

...

gcc -m32 -S -masm=intel -O1 prog.c

1 поток2 поток

▪ Вытеснение потока после записи младших бит приведёт к тому, что эти биты останутся в памяти, а старшие будут записаны другим потоком.

▪ На многоядерных системах даже не требуется вытеснения. 7

Page 8: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Фрагментированные чтения и записи

mov eax, DWORD PTR shared

mov edx, DWORD PTR shared+4

ret

uint64_t shared;

uint64_t getShared() {

return shared;

}

gcc -m32 -S -masm=intel -O1 prog.c

чтение младших 32 битчтение старших 32 бит

▪ Выполнение чтения 64-битного целого shared на 32-разрядной архитектуре выполняется за 2 инструкции.

▪ Операция чтения не атомарная.8

Page 9: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Фрагментированные чтения и записи

strd r0, r1, [r2]

▪ Инструкции могут быть неатомарными, даже если выполняются одной процессорной инструкцией.

Например, в ARMv7 инструкция для помещения содержимого двух 32-битных регистров в один 64-битный:

На некоторых процессорах эта инструкция реализуются двумя отдельными операциями сохранения. 32-битная операция mov атомарна только для выравненных данных. В остальных случаях операция неатомарная

▪ Вытеснение потоков, выполняющих данные операции, или выполнение операций в двугих потоках в многоядерных системах приводит к неопределённому поведению.

9

Page 10: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарность в С и С++

▪ В языках С и С++ предполагается, что все операции неатомарны.

▪ Операции могут быть атомарными в большинстве случаев, например, операция присваивания 32-битного целого значения.

▪ Тем не менее, все инструкции должны рассматриваться как неатомарные.

▪ К счастью, в С и С++ есть набор шаблонов атомарных типов данных.

10

Page 11: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарность в С и С++

▪ Атомарные операции в С++ неделимы. Из любого потока нельзя обнаружить эту операцию выполненной частично - она либо выполнена, либо невыполнена.

▪ Это позволяет избежать гонок данных.

▪ Для атомарных типов определён метод is_lock_free, позволяющий определить, являются ли операции над ним напрямую с помощью атомарных инструкций, или они эмулируются.

11

Page 12: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарные типы в С и С++

▪ std::atomic_flag - единственный тип, который не имеет функции is_lock_free. Он предельно простой, всецело атомарный и поддерживает одну операцию: test_and_set - проверить и установить.

▪ Остальные типы определяются специализацией шаблона std::atomic<>, например std::atomic<int> и std::atomic<void*>

12

Page 13: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарные типы в С и С++

Атомарные тип Соответствующая специализация

std::atomic_bool std::atomic<bool>

std::atomic_char std::atomic<char>

std::atomic_schar std::atomic<signed char>

std::atomic_uchar std::atomic<unsigned char>

std::atomic_short std::atomic<short>

std::atomic_ushort std::atomic<unsigned short>

std::atomic_int std::atomic<int>

std::atomic_uint std::atomic<unsigned int>

std::atomic_long std::atomic<long>

...

+ пользовательские типы13

Page 14: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операции над атомарными типами

▪ Операции сохранения: store, clear, etc. Упорядочение memory_order_relaxed, memory_order_release, memory_order_seq_cst.

▪ Операции загрузки: load, etc. Упорядочение memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_seq_cst.

▪ Операции чтения-модификации-записи: compare_exchange, fetch_add, test_and_set, etc. Упорядочение memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_seq_cst, memory_order_acq_rel.

14

Page 15: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарный флаг std::atomic_flag

std::atomic_flag должен быть проиниализирован:

std::atomic_flag flag = ATOMIC_FLAG_INIT

Очистить флаг (операция сохранения): установить значение false:

flag.clear(std::memory_order_release);

Установить значение флага в true и вернуть предыдущее значение:

bool x = flag.test_and_set();

Для атомарного флага запрещены операции копирования и присваивания.

15

Page 16: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Реализация спинлока на основе атомарного флага

class spinlock_mutex { std::atomic_flag flag;

public: spinlock_mutex(): flag{ATOMIC_FLAG_INIT} { }

void lock() { while (flag.test_and_set( std::memory_order_acquire)); }

void unlock() { flag.clear(std::memory_order_release); }};

n.b. spinlock_mutex можно использовать с lock_guard и unique_guard! 16

Записать в flag 1, вернуть то, что было

Записать 0 в flag

Page 17: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операции сохранения и загрузки атомарных типов

// Объявить переменную и проициализировать truestd::atomic<bool> b(true);

// Загрузить значение в переменной в неатомарную // переменную xbool x = b.load(std::memory_order_acquire);

// Записать в переменную b значение trueb.store(true);

// Обменять значение переменной b со значением false, // вернуть предыдущее значение b в переменную x.x = b.exchange(false, std::memory_order_acq_rel);

17

Page 18: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операция “сравнить и обменять”

Операция compare_exchange (“сравнить и обменять”):

1. Сравнить текущее значение атомарной переменной с ожидаемым expected.

2. Если значения совпали, сохранить новое значение desired и вернуть true.

3. Если значения не совпадают, то ожидаемое значение expected заменяется фактическим значением переменной, функция возвращает false.

bool compare_exchange_weak(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst);

bool compare_exchange_strong(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst);

18

Page 19: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операция “сравнить и обменять”

compare_exchange_weak() - сохранение может не произойти, даже если текущее значение совпадает с ожидаемым. Значение переменной не изменится, функция возвращает false.

Последнее возможно при отсутствии аппаратной поддержки команды сравнить-и-обменять, из-за того, что поток может быть вытеснен в середине требуемой последовательности команд (ложный отказ).

Из-за возможного ложного отказа функцию compare_exchange_weak() обычно вызывают в цикле:

bool expected = false;extern atomic<bool> b;...while (!b.compare_exchange_weak(expected, true);

19

Page 20: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операция “сравнить и обменять”

compare_exchange_strong() гарантирует замену переменной в случае выполнения условия.

▪ compare_exchange_strong() выгодно использовать в случае однократного выполнения операции, т.е. при необходимости заменить значение на жалаемое, и в случае, если вычисление нового значения занимает длительное время.

▪ Если функция compare_exchange вызывается в цикле, тогда предпочтительнее использовать compare_exchange_weak, чтобы избежать двойного цикла (compare_exchange_strong реализован в виде цикла на системах, которые не поддерживают атомарной операции сравнения и замены).

20

Page 21: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Атомарный тип atomic<T*>

Функции для типа atomic<T*>:

▪ is_lock_free, load, store, exchange, compare_exchange_weak, compare_exchange_strong

▪ обменять и прибавить:fetch_add, operator++, operator+=

▪ обменять и вычесть:fetch_sub, operator--, operator-=

class C {};C arr[10];std::atomic<C*> ptr(arr);C* x = ptr.fetch_add(2);assert(x == arr);assert(p.load() == &some_array[2]);p--; x = p;assert(x == &arr[1]);

операции чтения-модификации-записи

21

Page 22: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Стандартные атомарные целочисленные типы

Функции для типов стандартных атомарных целочисленных типов (int, unsigned int, long, unsigned long, etc):

▪ is_lock_free, load, store, exchange, compare_exchange_weak, compare_exchange_strong

▪ обменять и прибавить (fetch_add, operator++, operator+=) обменять и вычесть (fetch_sub, operator--, operator-=)

▪ operator&=, operator|=, operator^=

Отсутствуют операции:▫ умножения, деления, сдвига

22

Page 23: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Пользовательские атомарные типы

В качестве шаблона std::atomic<> может выступать тип, он должен удовлетворять требованиям

▪ В нём должен присутствовать тривиальный оператор присваивания. Нет виртуальных функций и виртуальных базовых классов, а оператор присваивания генерируется автоматически (например, memcpy)

▪ Тип должен допускать побитовое сравнение на равенство (например, с помощью memcmp)

23

Page 24: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метаморфозы программы или страшная правда

24

Page 25: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

О дивный новый и прекрасный параллельный мир!

Выполняет ли компьютер программу, которую вы написали?

25

Page 26: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

О дивный новый и прекрасный параллельный мир!

Выполняет ли компьютер программу, которую вы написали?

НЕТ26

Page 27: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

О дивный новый и прекрасный параллельный мир!

Выполняет ли компьютер программу, которую вы написали?

НЕТПросто дело в том что...

иерархическая структура памяти, внеочередное выполнение команд процессора и компиляторная оптимизация.

27

Page 28: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратно вызванные трансформации программы

кэш 2

кэш 1

Память

кэш 2

кэш 1 кэш 1 кэш 1

Процессорные ядра

28

Page 29: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратно вызванные трансформации программы

кэш 2

кэш 1

Память

кэш 2

кэш 1 кэш 1 кэш 1

Процессорные ядра

Когерентность кэша (MESI, MOESI, MESIF)

29

Page 30: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратно вызванные трансформации программы

кэш 2

кэш 1

Память

кэш 2

кэш 1 кэш 1 кэш 1

Процессорные ядра

Внеочередное выполнение инструкций (out-of-order execution)

Когерентность кэша (MESI, MOESI, MESIF)

30

Page 31: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратно вызванные трансформации программы

Intel Nehalem Core Pipeline

31

Page 32: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратно вызванные трансформации программы

32

Page 33: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Компиляторная оптимизация - виды оптимизаций

▪ Peephole-оптимизация▪ Локальная оптимизация▪ Внутрипроцедурная оптимизация▪ Оптимизация циклов▪ Межпроцедурная оптимизация

33

Page 34: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Компиляторная оптимизация - виды оптимизаций

▪ Peephole-оптимизация▪ Локальная оптимизация▪ Внутрипроцедурная оптимизация▪ Оптимизация циклов

▫ Анализ индуктивных переменных▫ Деление цикла на части▫ Объединение циклов▫ Инверсия цикла▫ Расщепление цикла

▪ Межпроцедурная оптимизация34

Page 35: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Компиляторная оптимизация - виды оптимизаций

-O-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments -fcompare-elim-fcprop-registers-fdce-fdefer-pop-fdelayed-branch-fdse-fforward-propagate-fguess-branch-probability-fif-conversion2-fif-conversion-finline-functions-called-once-fipa-pure-const-fipa-profile-fipa-reference-fmerge-constants-fmove-loop-invariants-fshrink-wrap-fsplit-wide-types-ftree-bit-ccp-ftree-ccp-fssa-phiopt-ftree-ch-ftree-copy-prop-ftree-copyrename-ftree-dce-ftree-dominator-opts-ftree-dse-ftree-forwprop-ftree-fre-ftree-phiprop-ftree-sink-ftree-slsr-ftree-sra-ftree-pta-ftree-ter-funit-at-a-time

-O2-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments -fcompare-elim-fcprop-registers-fdce-fdefer-pop-fdelayed-branch-fdse-fforward-propagate-fguess-branch-probability-fif-conversion2-fif-conversion-finline-functions-called-once-fipa-pure-const-fipa-profile-fipa-reference-fmerge-constants-fmove-loop-invariants-fshrink-wrap-fsplit-wide-types-ftree-bit-ccp-ftree-ccp-fssa-phiopt-ftree-ch-ftree-copy-prop-ftree-copyrename-ftree-dce-ftree-dominator-opts-ftree-dse-ftree-forwprop-ftree-fre-ftree-phiprop-ftree-sink-ftree-slsr-ftree-sra-ftree-pta-ftree-ter-funit-at-a-time

-fthread-jumps-falign-functions -falign-jumps-falign-loops -falign-labels-fcaller-saves-fcrossjumping-fcse-follow-jumps -fcse-skip-blocks-fdelete-null-pointer-checks-fdevirtualize -fdevirtualize-speculatively-fexpensive-optimizations-fgcse -fgcse-lm -fhoist-adjacent-loads-finline-small-functions-findirect-inlining-fipa-cp-fipa-sra-fipa-icf-fisolate-erroneous-paths- dereference-foptimize-sibling-calls-foptimize-strlen-fpartial-inlining-fpeephole2-freorder-blocks -freorder-blocks-and-partition -freorder-functions -frerun-cse-after-loop-fsched-interblock -fsched-spec-fschedule-insns -fschedule-insns2-fstrict-aliasing -fstrict-overflow -ftree-builtin-call-dce-ftree-switch-conversion -ftree-tail-merge-ftree-pre-ftree-vrp-fuse-caller-save

-O3-fauto-inc-dec -fbranch-count-reg -fcombine-stack-adjustments -fcompare-elim-fcprop-registers-fdce-fdefer-pop-fdelayed-branch-fdse-fforward-propagate-fguess-branch-probability-fif-conversion2-fif-conversion-finline-functions-called-once-fipa-pure-const-fipa-profile-fipa-reference-fmerge-constants-fmove-loop-invariants-fshrink-wrap-fsplit-wide-types-ftree-bit-ccp-ftree-ccp-fssa-phiopt-ftree-ch-ftree-copy-prop-ftree-copyrename-ftree-dce-ftree-dominator-opts-ftree-dse-ftree-forwprop-ftree-fre-ftree-phiprop-ftree-sink-ftree-slsr-ftree-sra-ftree-pta-ftree-ter-funit-at-a-time

-fthread-jumps-falign-functions -falign-jumps-falign-loops -falign-labels-fcaller-saves-fcrossjumping-fcse-follow-jumps -fcse-skip-blocks-fdelete-null-pointer-checks-fdevirtualize -fdevirtualize-speculatively-fexpensive-optimizations-fgcse -fgcse-lm -fhoist-adjacent-loads-finline-small-functions-findirect-inlining-fipa-cp-fipa-sra-fipa-icf-fisolate-erroneous-paths- dereference-foptimize-sibling-calls-foptimize-strlen-fpartial-inlining-fpeephole2-freorder-blocks -freorder-blocks-and-partition -freorder-functions -frerun-cse-after-loop-fsched-interblock -fsched-spec-fschedule-insns -fschedule-insns2-fstrict-aliasing -fstrict-overflow -ftree-builtin-call-dce-ftree-switch-conversion -ftree-tail-merge-ftree-pre-ftree-vrp-fuse-caller-save-finline-functions-funswitch-loops-fpredictive-commoning-fgcse-after-reload-ftree-loop-vectorize-ftree-loop-distribute-patterns-ftree-slp-vectorize-fvect-cost-model-ftree-partial-pre-fipa-cp-clone

35

Page 36: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Компиляторная оптимизация - примеры оптимизаций

x = 1;

y = 2;

x = 3;

for (i = 0; i < n; i++)

sum += a[i];

y = 2;

x = 3;

r1 = sum;

for (i = 0; i < n; i++)

r1 += a[i];

sum = r1;

for (i = 0; i < n; i++)

j = 42 * i;

j = -42

for (i = 0; i < n; i++)

j = j + 42;

36

Page 37: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Компиляторная оптимизация - примеры оптимизаций

x = Johann;

y = Sebastian;

z = Bach;

for (i = 0; i < n; i++)

for (j = 0; j < m;j++);

a[i][j] = 1;

z = Bach;

x = Johann;

y = Sebastian;

for (j = 0; j < n; j++)

for (i = 0; i < m;i++);

a[i][j] = 1;

for (i = 0; i < n; i++)

a[i] = 1;

for (i = 0; i < n; i++)

b[i] = 2;

for (i = 0; i < n; i++) {

a[i] = 1;

b[i] = 2;

} 37

Page 38: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Компиляторная оптимизация - примеры оптимизаций

Что компилятор знает:Все операции с памятью совершаются в текущем потоке, что они в точности означают, и какие существуют зависимости по данным.

Что компилятор не знает:Какие области памяти доступны и изменяются в разных потоках.

Как решить:Сказать! Как-то пометить операции, которые выполняются с разделяемыми переменными.

38

Page 39: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Этапы трансформации программы

Исходный код

Компиляторудаление подвыражений, свёртка констант, оптимизация циклов, ...

Процессорпредвыборка, спекулятивное выполнение инструкций, буферизация, HTM, ...

Реальное выполнение программы

Кэшчастные и общие кэши, буферы записи, ...

“Гораздо лучше выполнять другую программу - не ту, что вы написали. Вам на самом деле даже не хочется выполнять эту вашу чушь - вы хотите запускать другую программу! Всё это делается для вашего блага.”

39

Page 40: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Этапы трансформации программы

▪ Как правило нельзя определить, на каком уровне произошла трансформация.

▪ Трансформации на всех уровнях эквивалентны, что позволяет рассматривать их как переупорядочивание операций загрузки (loads) и записи (stores).

▪ Необходимое условие при выполнении трансформаций - сохранение иллюзии последовательно согласованного кода.

40

Исходный код

Компиляторудаление подвыражений, свёртка констант, оптимизация циклов, ...

Процессорпредвыборка, спекулятивное выполнение инструкций, буферизация, HTM, ...

Реальное выполнение программы

Кэшчастные и общие кэши, буферы записи, ...

Page 41: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency, SC)

“Результат выполнения программы такой, как если бы операции всех процессоров выполнялись последовательно и результат операции каждого отдельного процессора появлялся бы в этой последовательности в порядке, который определяется программой.” (Л. Лэмпорт, 1979)

▪ Рассмотрим многопроцессорную систему, состоящую из нескольких последовательных процессоров.

▪ Операции, выполняемые процессорами над некоторой областью памяти (страница, объект, адрес, ...), появляются в одном и том же порядке для всех процессоров, несмотря на то, что фактическая последовательность выполнения операций может быть другой.

41

Page 42: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency, SC)

“Результат выполнения программы такой, как если бы операции всех процессоров выполнялись последовательно и результат операции каждого отдельного процессора появлялся бы в этой последовательности в порядке, который определяется программой.” (Л. Лэмпорт, 1979)

▪ Рассмотрим многопроцессорную систему, состоящую из нескольких последовательных процессоров.

▪ Операции, выполняемые процессорами над некоторой областью памяти (страница, объект, адрес, ...), появляются в одном и том же порядке для всех процессоров, несмотря на то, что фактическая последовательность выполнения операций может быть другой.

И это прекрасно!

42

Page 43: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency, SC)

“Результат выполнения программы такой, как если бы операции всех процессоров выполнялись последовательно и результат операции каждого отдельного процессора появлялся бы в этой последовательности в порядке, который определяется программой.” (Л. Лэмпорт, 1979)

▪ Рассмотрим многопроцессорную систему, состоящую из нескольких последовательных процессоров.

▪ Операции, выполняемые процессорами над некоторой областью памяти (страница, объект, адрес, ...), появляются в одном и том же порядке для всех процессоров, несмотря на то, что фактическая последовательность выполнения операций может быть другой.

И это прекрасно!но...

43

Page 44: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency, SC)

… но вы этого не хотите!

▪ Скорее всего очень нерационально выполнять в точности то, что вы написали.

▪ Гораздо лучше выполнить нечто иное, которое бы работало так же, как и то, что вы написали, но выполнялось бы гораздо быстрее.

Поэтому▪ Мы (программное обеспечение ПО: компилятор и

аппаратное обеспечение АО: кэш, процессор) будем это делать!

▪ А вы (программисты), в свою очередь, должны обеспечить возможность корректной трансформации и выполнения программы так, чтобы сохранялась иллюзия последовательной согласованности, включив в свою программу необходимые ограничения. 44

Page 45: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Модель памяти - это договор

Вы обещаетеКорректно

реализовать синхронизацию

в вашей программе

(путём добавления необходимых инструкций в программу,

делающих её безопасной

относительно гонок)

Система обещает

Обеспечить иллюзию

выполнения той программы, которую вы написали.

(путём компиляции и выполнения)

45

Page 46: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Модель памяти - это договор

Вы обещаетеКорректно

реализовать синхронизацию

в вашей программе

(путём добавления необходимых инструкций в программу,

делающих её безопасной

относительно гонок)

Система обещает

Обеспечить иллюзию

выполнения той программы, которую вы написали.

(путём компиляции и выполнения)

Модель памяти определяет, какие действия вы должны совершить и как должна отреагировать система, чтобы

обеспечить выполнение операций с памятью в необходимой последовательности. 46

Page 47: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратное переупорядочивание инструкций

47

Page 48: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Аппаратное переупорядочивание инструкций

Первое правило робототехники компиляторов и процессоров при упорядочивании доступа к памяти:

Нельзя изменять поведение однопоточной программы.

▪ В однопоточных программах переупорядочивания остаются незамеченными.

▪ То же самое - при многопоточном программировании на основе мьютексов, семафоров и т.д.

▪ Но не при использовании атомарных переменных и техник программирования без блокировок.

48

Page 49: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Поток 1flag1 = 1;if (flag2 != 0) // ожидать освобождения // критической секцииelse // войти в критическую // секцию

Алгоритм Деккера позволяет решать проблему взаимного исключения (в теории), был опубликован в 1965 г.Он не приводит к взаимным исключениям (deadlock) и свободен от голодания (starvation).

Поток 2flag2 = 1;if (flag1 != 0) // ожидать освобождения // критической секцииelse // войти в критическую // секцию

49

Page 50: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Процессор 1 Процессор 2

flag2 = 1;

if (flag1 != 0)

{ … }

Память: flag1 = 0, flag2 = 0

flag1 = 1;

if (flag2 != 0)

{ … }

Store Buffer Store Buffer

50

Page 51: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Процессор 1 Процессор 2

Память: flag1 = 0, flag2 = 0

flag1 = 1;

if (flag2 != 0)

{ … }

flag2 = 1;

if (flag1 != 0)

{ … }

Store Bufferflag1 = 1

Store Buffer

Сохранение 1 в буфере

51

Page 52: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Процессор 1 Процессор 2

Память: flag1 = 0, flag2 = 0

flag1 = 1;

if (flag2 != 0)

{ … }

flag2 = 1;

if (flag1 != 0)

{ … }

Store Bufferflag1 = 1

Сохранение 1 в буфере

Сохранение 1 в буфере

Store Bufferflag1 = 1

52

Page 53: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Процессор 1 Процессор 2

Память: flag1 = 0, flag2 = 0

flag1 = 1;

if (flag2 != 0)

{ … }

flag2 = 1;

if (flag1 != 0)

{ … }

Store Bufferflag1 = 1

Сохранение 1 в буфере

Сохранение 1 в буфере

Store Bufferflag1 = 1

Чтение 0 для flag2

Чтение 0 для flag1

StoreLoad

53

Page 54: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Процессор 1 Процессор 2

Память: flag1 = 0, flag2 = 0

flag1 = 1;

if (flag2 != 0)

{ … }

flag2 = 1;

if (flag1 != 0)

{ … }

Store Bufferflag1 = 1

Сохранение 1 в буфере

Сохранение 1 в буфере

Store Bufferflag1 = 1

Чтение 0 для flag2

Чтение 0 для flag1

54

Page 55: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание на примере алгоритма Деккера

Процессор 1 Процессор 2

Память: flag1 = 1, flag2 = 1

flag1 = 1;

if (flag2 != 0)

{ … }

flag2 = 1;

if (flag1 != 0)

{ … }

Store Bufferflag1 = 1

Сохранение 1 в буфере

Сохранение 1 в буфере

Store Bufferflag1 = 1

Чтение 0 для flag2

Чтение 0 для flag1

Сброс буфера (flag1)

Сброс буфера (flag2)

55

Page 56: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в различных процессорах

Тип переупоря-дочивания / архитектуры

Alpha ARMv7 POWER SPARC RMO

SPARC PSO

SPARC TSO

x86 AMD64 IA-64

Loads после loads

Loads после stores

Stores после stores

Stores после loads

АО с loads

АО с stores

Зависимые loads

АО - атомарные операции 56

Page 57: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в различных процессорах

IBM Blue Gene

Смартфоны

DEC AlphaXbox 360

PowerPC

ARM

SPARC TSO

x86 / 64

более сильное упорядочивание(strong model, sequential consistency)

более слабое упорядочивание(weak model, relaxed ordering)

Как правило сильное упорядочивание

Ослабленное упорядочивание с поддержкой зависимостей

по данным

Вполне ослабленное

упорядочивание

PowerMac

57

Page 58: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в различных процессорах

IBM Blue Gene

Смартфоны

DEC AlphaXbox 360

PowerPC

ARM

SPARC TSO

x86 / 64

более сильное упорядочивание(strong model, sequential consistency)

более слабое упорядочивание(weak model, relaxed ordering)

Как правило сильное упорядочивание

Ослабленное упорядочивание с поддержкой зависимостей

по данным

Вполне ослабленное

упорядочивание

PowerMac

При сильном упорядочивании (сильная модель памяти) каждая инструкция неявно реализует семантику захвата и освобождения.

При слабом упорядочивании (слабая модель памяти) не накладывается никаких ограничений на порядок выполнения инструкций.

58

Page 59: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

IBM Blue Gene

Смартфоны

DEC AlphaXbox 360

PowerPC

ARM

SPARC TSO

x86 / 64

более сильное упорядочивание(strong model, sequential consistency)

более слабое упорядочивание(weak model, relaxed ordering)

Как правило сильное упорядочивание

Ослабленное упорядочивание с поддержкой зависимостей

по данным

Вполне ослабленное

упорядочивание

PowerMac

59

Page 60: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Intel Architectures Software Developer’s Manual, Vol. 3:

▪ Операции чтения не могут быть переупорядочены с другими операциями чтения

▪ Операции записи не могут быть переупорядочены с другими операциями записями

▪ Операции записи не могут быть переупорядочены с другими операциями записи, кроме следующих исключений: …

▪ Операции чтения могут быть переупорядочены с более старыми операциями записи в другие области памяти, но не с операциями записи в ту же область.

▪ Операции чтения не могут перейти раньше инструкций LFENCE, MFENCE, операции записи - раньше инструкций LFENCE, SFENCE, MFENCE.

▪ LFENCE, SFENCE, MFENCE не могут выполниться раньше операций чтения, записи, того или другого соответственно.

60

Page 61: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Процессор 1mov x, 1 ; запись (store) ; 1 в x

mov r1, y ; загрузка (load) ; из y в регистр

Процессор 2mov y, 1 ; запись (store) ; 1 в x

mov r2, x ; загрузка (load) ; из y в регистр

Возможные варианты:

▪ r1 = 0, r2 = 1

▪ r1 = 1, r2 = 0

▪ r1 = 1, r2 = 1

▪ r1 = 0, r2 = 0

x = 0, y = 0

61

Page 62: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Процессор 1mov x, 1 ; запись (load) ; 1 в x

mov r1, y ; загрузка (store) ; из y в регистр

Процессор 2mov y, 1 ; запись (load) ; 1 в x

mov r2, x ; загрузка (store) ; из y в регистр

▪ r1 = 0, r2 = 0

В процессорах архитектуры x86 достустима перестановка операция load после store. Или, то же, операции store могут выполняться до операций load.

x = 0, y = 0

StoreLoad

62

Page 63: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Поток 1x = 1;

asm volatile("" ::: "memory");

r1 = y;

Программный барьер памяти: запретить переупорядочивание инструкций компилятором.

63

Page 64: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Поток 1x = 1;

asm volatile("" ::: "memory");

r1 = y;

Поток 3if (r1 == 0 && r2 == 0) printf("reordering happened!\n");

Поток 2y = 1;

asm volatile("" ::: "memory");

r2 = x;

64

Переупорядочивание может произойти!

Page 65: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Поток 1x = 1;

asm volatile("" ::: "memory");

r1 = y;

Поток 3if (r1 == 0 && r2 == 0) printf("reordering happened!\n");

Поток 2y = 1;

asm volatile("" ::: "memory");

r2 = x;

65

Page 66: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Поток 1x = 1;

asm volatile("mfence" ::: "memory");asm volatile("" ::: "memory");

r1 = y;

Поток 2y = 1;

asm volatile("mfence" ::: "memory");asm volatile("" ::: "memory");

r2 = x;

Поток 3if (r1 == 0 && r2 == 0) printf("reordering happened!\n");

66

Page 67: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Поток 1x = 1;

asm volatile("mfence" ::: "memory");asm volatile("" ::: "memory");

r1 = y;

Программный барьер памяти: запретить переупорядочивание инструкций компилятором.

Аппаратный барьер памяти: запретить переупорядочивание инструкций процессором.

67

mov DWORD PTR X[rip], 1mfencemov eax, DWORD PTR Y[rip]...mov DWORD PTR r1[rip], eax

полный барьер памяти

Page 68: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах архитектуры x86

Поток 1x = 1;

asm volatile("mfence" ::: "memory");asm volatile("" ::: "memory");

r1 = y;

Поток 3if (r1 == 0 && r2 == 0) printf("reordering happened!\n");

Переупорядочивание не произойдёт!

Поток 2y = 1;

asm volatile("mfence" ::: "memory");asm volatile("" ::: "memory");

r2 = x;

68

Page 69: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

IBM Blue Gene

Смартфоны

DEC AlphaXbox 360

PowerPC

ARM

SPARC TSO

x86 / 64

более сильное упорядочивание(strong model, sequential consistency)

более слабое упорядочивание(weak model, relaxed ordering)

Как правило сильное упорядочивание

Ослабленное упорядочивание с поддержкой зависимостей

по данным

Вполне ослабленное

упорядочивание

PowerMac

69

Page 70: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

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

int sharedCount; // глобальный счётчик

void IncShared() { int count = 0; // локальный счётчик

while (count < N) { randomBusyWork(); // случайная задержка

// наивная реализация мьютекса int expected = 0; if (flag.compare_exchange_strong(expected, 1, std::memory_order_relaxed)); { sharedVal++; // выполняется под защитой мьютекса flag.store(0, std::memory_order_relaxed)) count++; } }

70

Page 71: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

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

int sharedCount; // глобальный счётчик

void IncShared() { int count = 0; // локальный счётчик

while (count < N) { randomBusyWork(); // случайная задержка

// наивная реализация мьютекса int expected = 0; if (flag.compare_exchange_strong(expected, 1, std::memory_order_relaxed)); { sharedVal++; // выполняется под защитой мьютекса flag.store(0, std::memory_order_relaxed)) count++; } } StoreStore

71

Page 72: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

int sharedCount; // глобальный счётчик

void IncShared() { int count = 0; // локальный счётчик

while (count < N) { randomBusyWork(); // случайная задержка

// наивная реализация мьютекса int expected = 0; if (flag.compare_exchange_strong(expected, 1, std::memory_order_relaxed)); { sharedVal++; // выполняется под защитой мьютекса asm volatile("" ::: "memory"); flag.store(0, std::memory_order_relaxed)) count++; } }

StoreStore

Переупорядочивание в процессорах с ослабленным упорядочиванием

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

запрет компиляторного переупорядочивания 72

Page 73: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

Поток 1int sharedCount; void IncShared() { int count = 0;

while (count < N) { randomBusyWork(); int expected = 0; if (...) { sharedVal++; asm volatile(...); flag.store(0, ...) count++; } }

Поток 2int sharedCount; void IncShared() { int count = 0;

while (count < N) { randomBusyWork(); int expected = 0; if (...) { sharedVal++; asm volatile(...); flag.store(0, ...) count++; } }

73

Page 74: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

Поток 1int sharedCount; void IncShared() { int count = 0;

while (count < N) { randomBusyWork(); int expected = 0; if (...) { sharedVal++; asm volatile(...); (1) flag.store(0, ...); count++; } }

Поток 2int sharedCount; void IncShared() { int count = 0;

while (count < N) { randomBusyWork(); int expected = 0; if (...) { sharedVal++; asm volatile(...); flag.store(0, ...) count++; } }

74

Page 75: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

Поток 1int sharedCount; void IncShared() { int count = 0;

while (count < N) { randomBusyWork(); int expected = 0; if (...) {(2) sharedVal++; asm volatile(...); (1) flag.store(0, ...); count++; } }

Поток 2int sharedCount; void IncShared() { int count = 0;

while (count < N) { randomBusyWork(); int expected = 0; if (...) {(3) sharedVal++; asm volatile(...); flag.store(0, ...) count++; } }

75

Page 76: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание в процессорах с ослабленным упорядочиванием

$ ./prog 100000 // N = 100000

sharedCount = 199348

sharedCount = 199034

sharedCount = 199517

sharedCount = 199829

sharedCount = 199113

sharedCount = 199566

Допустим N = 100000

Каждый из 2 потоков выполняет 100000 операций инкремента разделяемой переменной sharedCount++.

Ожидаемое значение: sharedVal = 200000

В реальности:

76

Page 77: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание при выполнении операция захвата-освобождения в процессорах архитектуры POWER

Поток 1 (процессор 1)

// Подготавливаем данные// и устанавливаем флаг// готовностиfor (i = 0; i < n; i++) { widget[i].x = x; widget[i].y = y; widget[i].ready = true;}

Поток 2 (процессор 2)// Если данные готовы,// обрабатываем их

for (i = 0; i < n; i++) { if (widget[i].ready) { do_some_stuff(widget[i]); }}

L2-кэш

Буфер 1 Буфер 2 Буфер N

... ...

77

Page 78: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание при выполнении операция захвата-освобождения в процессорах архитектуры POWER

Поток 1 (процессор 1)

// Подготавливаем данные// и устанавливаем флаг// готовностиfor (i = 0; i < n; i++) { widget[i].x = x; widget[i].y = y; widget[i].ready = true;}

Поток 2 (процессор 2)// Если данные готовы,// обрабатываем их

for (i = 0; i < n; i++) { if (widget[i].ready) { do_some_stuff(widget[i]); }}

L2-кэш

Буфер 1 Буфер 2 Буфер N

... ...

78

Page 79: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание при выполнении операция захвата-освобождения в процессорах архитектуры POWER

Поток 1 (процессор 1)

// Подготавливаем данные// и устанавливаем флаг// готовностиfor (i = 0; i < n; i++) { widget[i].x = x; widget[i].y = y; widget[i].ready = true;}

Поток 2 (процессор 2)// Если данные готовы,// обрабатываем их

for (i = 0; i < n; i++) { if (widget[i].ready) { do_some_stuff(widget[i]); }}

L2-кэш

Буфер 1 Буфер 2 Буфер N

... ...

79

Page 80: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание при выполнении операция захвата-освобождения в процессорах архитектуры POWER

Поток 1 (процессор 1)

// Подготавливаем данные// и устанавливаем флаг// готовностиfor (i = 0; i < n; i++) { widget[i].x = x; widget[i].y = y; widget[i].ready = true;}

Поток 2 (процессор 2)// Если данные готовы,// обрабатываем их

for (i = 0; i < n; i++) { if (widget[i].ready) { do_some_stuff(widget[i]); }}

L2-кэш

Буфер 1 Буфер 2 Буфер N

... ...

80

Page 81: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание при выполнении операция захвата-освобождения в процессорах архитектуры POWER

Поток 1 (процессор 1)

// Подготавливаем данные// и устанавливаем флаг// готовностиfor (i = 0; i < n; i++) { widget[i].x = x; widget[i].y = y; widget[i].ready = true;}

Поток 2 (процессор 2)// Если данные готовы,// обрабатываем их

for (i = 0; i < n; i++) { if (widget[i].ready) { do_some_stuff(widget[i]); }}

L2-кэш: widget[i].y = y; widget[i].ready = true;

... ...

81

Page 82: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Переупорядочивание при выполнении операция захвата-освобождения в процессорах архитектуры POWER

Поток 1 (процессор 1)

// Подготавливаем данные// и устанавливаем флаг// готовностиfor (i = 0; i < n; i++) { widget[i].x = x; widget[i].y = y; widget[i].ready = true;}

Поток 2 (процессор 2)// Если данные готовы,// обрабатываем их

for (i = 0; i < n; i++) { if (widget[i].ready) { do_some_stuff(widget[i]); }}

L2-кэш: widget[i].y = y; widget[i].ready = true;

... ...

StoreStore

82

Page 83: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций

83

Page 84: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций

Первое правило робототехники компиляторов и процессоров при упорядочивании доступа к памяти:

Нельзя изменять поведение однопоточной программы.

▪ В однопоточных программах переупорядочивания остаются незамеченными.

▪ То же самое - при многопоточном программировании на основе мьютексов, семафоров и т.д.

▪ Но не при использовании атомарных переменных и техник программирования без блокировок.

84

Page 85: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций

mov eax, DWORD PTR y[rip]add eax, 111mov DWORD PTR x[rip], eaxmov DWORD PTR y[rip], 222

int x, y;

int main() { x = y + 111; y = 222; printf("%d%d", x, y);

gcc -S -masm=intel prog.c

выполнение командыx = y + 111 завершеновыполнение командыy = 222 завершено

85

Page 86: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций

mov eax, DWORD PTR y[rip]mov edx, 222...mov DWORD PTR y[rip], 222lea esi, [rax+111]...mov DWORD PTR x[rip], esi

int x, y;

int main() { x = y + 111; y = 222; printf("%d%d", x, y);

gcc -S -masm=intel -O2 prog.c

выполнение командыy = 222 завершено

выполнение командыx = y + 111 завершено

y = 222 выполняется раньше x = y + 111

86

Page 87: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций

mov eax, DWORD PTR y[rip]add eax, 111mov DWORD PTR x[rip], eaxmov esi, DWORD PTR x[rip]mov edx, 222...xor eax, eaxmov DWORD PTR y[rip], 222

int x, y;

int main() { x = y + 111; asm volatile("" ::: "memory"); y = 222; printf("%d%d", x, y);

gcc -S -masm=intel -O2 prog.c

явный барьер

87

Page 88: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

int data;bool isReleased = false; // данные опубликованы?

void releaseData(int val) // опубликовать данные{ data = val; // записать данные isReleased = true; // данные опубликованы!} // можно с ними работать

88

Page 89: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

Данные должны быть проинициализированы в 1 потоке перед тем, как они будут использованы во 2 потоке.

89

Page 90: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

1. Данные проиницаилизрованы

90

Page 91: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

1. Данные проициализированы

2. Ура! Второй поток может обрабатывать

91

Page 92: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

92

Page 93: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

Из-за переупорядочивания инструкций компилятором флаг выставляется до того, как данные готовы.

93

StoreStore

Page 94: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

Из-за переупорядочивания инструкций компилятором флаг выставляется до того, как данные готовы.

StoreStore

94

Page 95: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

Из-за переупорядочивания инструкций компилятором флаг выставляется до того, как данные готовы.

95

Page 96: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); doSomething(data);}

96

Page 97: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; asm volatile("" ::: "memory"); isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); asm volatile("" ::: "memory"); doSomething(data);}

97

Page 98: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Программное переупорядочивание инструкций на примере с публикацией данных (операция захвата-освобождения)

Поток 1int data;bool isReleased = false;

void releaseData(int val) { data = val; asm volatile("" ::: "memory"); isReleased = true; }

Поток 2

void utilizeData(){ while (!isReleased); asm volatile("" ::: "memory"); doSomething(data);}

Операция записи-освобождения

Операция чтения-захвата

98

Page 99: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операции сохранения из чистого воздуха (out-of-thin air stores)

if (x > 0)

y++;

register int r = y;

if (x > 0)

r++;

y = r;

Размещение переменной в регистре в процессе оптимизирующей компиляции

создание новой регистровой переменной

Новая операция сохранения (store) “из чистого воздуха”

Создание операций сохранения “из чистого воздуха” не допустимо в соответствии с последним стандартом, однако... 99

Page 100: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операции сохранения из чистого воздуха (out-of-thin air stores)

static pthread_mutex_t lock = PTHREAD_MUTEX_INITALIZER;static int count = 0;int trylock() { int rc; rc = pthread_mutex_trylock(&mutex); if (rc == 0) count++;

однако в С & PThreads такая оптимизация допускается:

static int count = 0;int trylock() { register int r = count; int rc; rc = pthread_mutex_trylock(&mutex); if (rc == 0) count++; count = r;

новый store и новая гонка данных! 100

Page 101: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Базовое отношение happens-before (происходит-раньше)

101

Page 102: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение happens-before (происходит-раньше)

Отношение happens-before определяет, какие операции видят последствия других операций.

Допустим A и В - операции в многопоточной программе. Тогда если А происходит-раньше В, тогда эффект (результат операции, который отразился в памяти) операции А становится видим для потока, выполняющего операцию В.

x = 10; // A

y = x + 1; // B

102

Page 103: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение happens-before (происходит-раньше)

Отношение happens-before определяет, какие операции видят последствия других операций.

Допустим A и В - операции в многопоточной программе. Тогда если А происходит-раньше В, тогда эффект (результат операции, который отразился в памяти) операции А становится видим для потока, выполняющего операцию В.

x = 10;

y = x + 1;

z = sqrt(x * y);

Все соотношения happens-before для операции А (x = 10)

103

Page 104: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

x = 10;

y = x + 1;

z = sqrt(x * y);

m = k - 5;

print(m)

print(x)

Отношение happens-before (происходит-раньше)

Отношение happens-before определяет, какие операции видят последствия других операций.

Допустим A и В - операции в многопоточной программе. Тогда если А происходит-раньше В, тогда эффект (результат операции, который отразился в памяти) операции А становится видим для потока, выполняющего операцию В.

104

Page 105: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 1 Поток 2

x = 10;

y = x + 1;

z = sqrt(x * y);

m = k - 5;

print(m)

w = x + 2

Отношение happens-before (происходит-раньше)

Отношение happens-before определяет, какие операции видят последствия других операций.

Допустим A и В - операции в многопоточной программе. Тогда если А происходит-раньше В, тогда эффект (результат операции, который отразился в памяти) операции А становится видим для потока, выполняющего операцию В.

105

Page 106: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение happens-before определяет, какие операции видят последствия других операций.

Допустим A и В - операции в многопоточной программе. Тогда если А происходит-раньше В, тогда эффект (результат операции, который отразился в памяти) операции А становится видим для потока, выполняющего операцию В.

Происходит-раньше ≠ происходит раньше

1. Из того, что А происходит-раньше В не следует, что А происходит раньше В.

2. Из того, что А происходит раньше В не следует, что А происходит-раньше В

106

Page 107: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит-раньше не означает происходит раньше

int x, y;

int main() { x = y + 111; // A y = 222; // B printf("%d%d", x, y);

1. Из того, что А происходит-раньше В не следует, что А происходит раньше В.

107

Page 108: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит-раньше не означает происходит раньше

mov eax, DWORD PTR y[rip]mov edx, 222...mov DWORD PTR y[rip], 222lea esi, [rax+111]...mov DWORD PTR x[rip], esi

int x, y;

int main() { x = y + 111; // A y = 222; // B printf("%d%d", x, y);

gcc -S -masm=intel -O2 prog.c

1. Из того, что А происходит-раньше В не следует, что А происходит раньше В.

108

Page 109: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит-раньше не означает происходит раньше

mov eax, DWORD PTR y[rip]mov edx, 222...mov DWORD PTR y[rip], 222lea esi, [rax+111]...mov DWORD PTR x[rip], esi

int x, y;

int main() { x = y + 111; y = 222; printf("%d%d", x, y);

gcc -S -masm=intel -O2 prog.c

выполнение командыy = 222 завершено

выполнение командыx = y + 111 завершено

y = 222 выполняется раньше x = y + 111

1. Из того, что А происходит-раньше В не следует, что А происходит раньше В.

109

Page 110: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит раньше не означает происходит-раньше

2. Из того, что А происходит раньше В не следует, что А происходит-раньше В

Поток 2

if (ready) // B

print(x);

Поток 1

x = 42

ready = true; // A

int x;bool ready = false;

110

Page 111: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит раньше не означает происходит-раньше

2. Из того, что А происходит раньше В не следует, что А происходит-раньше В

Поток 2

if (ready) // B

print(x);

Поток 1

x = 42

ready = true; // A

int x;bool ready = false;

111

Page 112: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит раньше не означает происходит-раньше

2. Из того, что А происходит раньше В не следует, что А происходит-раньше В

Поток 2

if (ready)

print(x);

Поток 1

x = 42

ready = true;

int x;bool ready = false;

112

происходит-раньше

Page 113: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Происходит раньше не означает происходит-раньше

2. Из того, что А происходит раньше В не следует, что А происходит-раньше В

Поток 2

if (ready)

print(x);

Поток 1

x = 42

ready = true;

int x;bool ready = false;

113

происходит-раньше

Page 114: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение happens-before определяет, какие операции видят последствия других операций.

Допустим A и В - операции в многопоточной программе. Тогда если А происходит-раньше В, тогда эффект (результат операции, который отразился в памяти) операции А становится видим для потока, выполняющего операцию В.

Происходит-раньше ≠ происходит раньше

1. Из того, что А происходит-раньше В не следует, что А происходит раньше В.

2. Из того, что А происходит раньше В не следует, что А происходит-раньше В

Отношение происходит-раньше имеет место тогда (и только тогда), когда это определёно стандартом языка.

114

Page 115: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Виды упорядочивания инструкций в С++

115

Page 116: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency)

std::atomic<int> x{0}, y{0}, v{0}, w{0}

void thread1() { x.store(1, std::memory_order_seq_cst); v.store(y.load(std::memory_order_seq_cst), std::memory_order_seq_cst);}

void thread2() { y.store(1, std::memory_order_seq_cst); w.store(x.load(std::memory_order_seq_cst), std::memory_order_seq_cst);}

int main() { std::thread t1{thread1}, t2{thread2}; t1.join(); t2.join(); assert(v != 0 || w != 0); assert не сработает

116

Page 117: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency)

std::atomic<int> data{0};std::atomic<bool> ready{false};

int main() {

std::thread producer{[]{ data.store(42, std::memory_order_seq_cst); ready.store(true, std::memory_order_seq_cst); }};

std::thread consumer{[]{ while (!ready.load(std::memory_order_seq_cst)) { } std::cout << data.load(std::memory_order_seq_cst); }};

producer.join(); consumer.join();

42

117

Page 118: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательная согласованность (sequential consistency)

std::atomic<int> z{0};std::atomic<bool> x{false}, y{false};

int main(int argc, const char *argv[]) {

std::thread store_y{[]{ x.store(true, std::memory_order_seq_cst); }};

std::thread store_x{[]{ y.store(true, std::memory_order_seq_cst); }};

std::thread read_x_then_y{[]{ while (!x.load(std::memory_order_seq_cst)) { } if (y.load(std::memory_order_seq_cst)) z.fetch_add(1, std::memory_order_seq_cst); }};

std::thread read_y_then_x{[]{ while (!y.load(std::memory_order_seq_cst)) { } if (y.load(std::memory_order_seq_cst)) z.fetch_add(1, std::memory_order_seq_cst); }};

store_x.join(); store_y.join(); read_x_then_y.join(); read_y_then_x.join(); std::cout << z.load(std::memory_order_seq_cst);

z > 0

118

Page 119: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Ослабленное упорядочение (relaxed ordering)

std::atomic<int> x{0}, y{0}, v{0}, w{0}

void thread1() { x.store(1, std::memory_order_relaxed); v.store(y.load(std::memory_order_relaxed), std::memory_order_relaxed);}

void thread2() { y.store(1, std::memory_order_relaxed); w.store(x.load(std::memory_order_relaxed), std::memory_order_relaxed);}

int main() { std::thread t1{thread1}, t2{thread2}; t1.join(); t2.join(); assert(v != 0 || w != 0);

assert может сработать

119

Page 120: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Ослабленное упорядочение (relaxed ordering)

std::atomic<int> data{0};std::atomic<bool> ready{false};

int main() {

std::thread producer{[]{ data.store(42, std::memory_order_relaxed); ready.store(true, std::memory_order_relaxed); }};

std::thread consumer{[]{ while (!ready.load(std::memory_order_relaxed)) { } std::cout << data.load(std::memory_order_relaxed); }};

producer.join(); consumer.join();

42 не гарантируется

120

Page 121: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Ослабленное упорядочение (relaxed ordering)

std::atomic<int> z{0};std::atomic<bool> x{false}, y{false};

int main(int argc, const char *argv[]) {

std::thread store_y{[]{ x.store(true, std::memory_order_relaxed); }};

std::thread store_x{[]{ y.store(true, std::memory_order_relaxed); }};

std::thread read_x_then_y{[]{ while (!x.load(std::memory_order_relaxed)) { } if (y.load(std::memory_order_relaxed)) z.fetch_add(1, std::memory_order_relaxed); }};

std::thread read_y_then_x{[]{ while (!y.load(std::memory_order_relaxed)) { } if (y.load(std::memory_order_relaxed)) z.fetch_add(1, std::memory_order_relaxed); }};

store_x.join(); store_y.join(); read_x_then_y.join(); read_y_then_x.join(); std::cout << z.load(std::memory_order_relaxed);

z >= 0

121

Page 122: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

34945-32109711

Иван

Значение переменной x

x.load(memory_order_relaxed)

122

Page 123: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

34945-32109711

Иван

Значение переменной x

123

x.load(memory_order_relaxed)

Page 124: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

34945-32109711

Иван

Значение переменной x

124

x.load(memory_order_relaxed)

encore!

Page 125: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

34945-32109711

Значение переменной x

x.load(memory_order_relaxed)

Иван

125

Page 126: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

34945-32109711-8

Иван

Значение переменной x

x.store(-8, memory_order_relaxed)

126

Page 127: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

34945-32109711-8

Значение переменной x

x.load(memory_order_relaxed)

Иван

127

Page 128: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора человека с блокнотом

Иван

Сергей

Анна

...34945-32109711-8

Иван

Анна Сергей

Значение переменной x

128

Page 129: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры памяти

129

Page 130: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Виды переупорядочиваний

StoreLoad StoreStore

LoadStoreLoadLoad

130

Page 131: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Иерархическая структура современных многоядерных систем

кэш 2

кэш 1

Память

кэш 2

кэш 1 кэш 1 кэш 1

Процессорные ядра

131

Page 132: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

кэш L1

2

кэш L1

Память

132

Page 133: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

кэш L1

2

кэш L1

Память

mov [x], 1mov r1, [y]

mov [y], 1mov r2, [x]

133

Page 134: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

134

Page 135: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

Утечка данных из центрального репозитория в локальный и обратно

135

Page 136: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1

x = 1

x = 0

Утечка данных из центрального репозитория в локальный и обратно

x = 0

136

Page 137: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1

x = 1

x = 1

Утечка данных из центрального репозитория в локальный и обратно

x = 0

137

Page 138: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1

x = 1

x = 1

Утечка данных из центрального репозитория в локальный и обратно

x = 1

138

Page 139: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1

x = 1

x = ?

x = ?

Неизвестно, когда изменения распространятся

на другие потоки.

139

Page 140: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1mov r1, [y]

mov [y], 1mov r2, [x]

x = 0y = 0

x = 0y = 0

x = 0y = 0

140

Page 141: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1mov r1, [y]

mov [y], 1mov r2, [x]

x = 0y = 1

x = 1y = 0

x = 0y = 0

141

Page 142: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Метафора репозитория

1

2

Рекс

Мухтар

Центральный репозиторий

mov [x], 1mov r1, [y]

mov [y], 1mov r2, [x]

x = ? {0,1}y = 1

x = 1y = ? {0,1}

x = ? {0,1}y = ? {0,1}

142

Page 143: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Виды барьеров

StoreLoad StoreStore

LoadStoreLoadLoad

143

Page 144: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер LoadLoad

1

Рекс

Центральный репозиторий

LoadLoad

x = 1y = 0

x = 1y = 0

git pull, hg pull, svn update, cvs update

Барьер LoadLoad:

▪ Предотвращает переупорядочивания между загрузками до барьера и загрузками после барьера.

▪ Гарантирует, что загруженные из центрального репозитория (памяти) в локальный репозиторий (кэш) значения будут по крайней мере такие же новые, как и последнее значение, которое “просочилось” из центрального репозитория. 144

Page 145: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер LoadLoad

1

Рекс

Центральный репозиторий

LoadLoad

x = 1y = 0

x = 1y = 0

git pull, hg pull, svn update, cvs update

// Так получилось, что // widget.ready = true утекло // в локальный репозиторийif (widget.ready) { // Подгрузить всё остальное // содержимое widget - // такое же “свежее”, как ready LoadLoadFence(); do_something(widget);} 145

Page 146: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreStore

1

Рекс

Центральный репозиторий

StoreStore

x = 1y = 0

Барьер StoreStore:

▪ Предотвращает переупорядочивания между сохранениями до барьера и сохранениями после барьера.

▪ Гарантирует, что загруженные из локального репозитория (кэш) в локальный репозиторий (память) значения будут по крайней мере такие же новые, как и последнее значение, которое “просочилось” из локального репозитория.

x = 1y = 0

git push, hg push, svn commit, cvs commit

146

Page 147: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreStore

1

Рекс

Центральный репозиторий

StoreStore

x = 1y = 0

x = 1y = 0

git push, hg push, svn commit, cvs commit

widget.x = x;widget.y = y;StoreStoreFence();widget.ready = true;

// Если ready = true просочится // Мухтару, то он увидит увидит// на центральном репозитории// всё остальные поля widget, // которые для него подготовил Рекс 147

Page 148: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер LoadStore

1

Рекс

mov r1, [y]mov r2, [x]mov [z], 42mov [w], r3mov [v], r4

Операции загрузки load

Операции сохранения store

Переупорядочивание LoadStore1. Есть набор инструкций, состоящий из операций

сохранения и загрузки.

148

Page 149: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер LoadStore

1

Рекс

mov r1, [y]mov r2, [x]mov [z], 42mov [w], r3mov [v], r4

Операции загрузки load - отложены

Операции сохранения store - выполнены

Переупорядочивание LoadStore1. Есть набор инструкций, состоящий из операций

сохранения и загрузки.

2. Если Рекс встречает операцию загрузки, то он просматривает следующие операции сохранения, и если они абсолютно не связаны с текущей операцией загрузки, то он откладывает выполнение операции загрузки и в первую очередь выполняет операции сохранения. 149

Page 150: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер LoadStore

1

Рекс

mov r1, [y]mov r2, [x]mov [z], 42mov [w], r3mov [v], r4

Будут промахи по кэшу...

Будут попадания в кэш...

Переупорядочивание LoadStore1. Есть набор инструкций, состоящий из операций

сохранения и загрузки.

2. Если Рекс встречает операцию загрузки, которые промахиваются по кэшу, то он просматривает следующие операции сохранения, которые попадают в кэш, и если они абсолютно не связаны с текущей операцией загрузки, то он откладывает выполнение операции загрузки и в первую очередь выполняет операции сохранения. 150

Page 151: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер LoadStore

1

Рекс

mov r1, [y]mov r2, [x]LoadStoremov [z], 42mov [w], r3mov [v], r4

Будут промахи по кэшу...

Будут попадания в кэш...

Переупорядочивание LoadStore1. Есть набор инструкций, состоящий из операций

сохранения и загрузки.

2. Если Рекс встречает операцию загрузки, которые промахиваются по кэшу, то он просматривает следующие операции сохранения, которые попадают в кэш, и если они абсолютно не связаны с текущей операцией загрузки, то он откладывает выполнение операции загрузки и в первую очередь выполняет операции сохранения. 151

Page 152: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreLoad

1

Рекс

mov [x], 1mov r1, [y]

2

Мухтар

mov [y], 1mov r2, [x]

x = 1y = 0

x = 0y = 1

r1 = 0

r2 = 0

152

Page 153: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreLoad

1

Рекс

mov [x], 1StoreLoadmov r1, [y]

2

Мухтар

mov [y], 1StoreLoadmov r2, [x]

x = 1y = ?

x = ?y = 1

Барьер StoreLoad:

▪ Гарантирует видимость для других процессоров всех операций сохранения, выполненных до барьера.

▪ Обеспечивает для всех операций загрузки, выполненных после барьера, получение результатов, которые имеют место во время барьера.

▪ Барьер предотвращает r1 = r2 = 0

▪ StoreLoad ≠ StoreStore + LoadLoad

153

Page 154: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreLoad

1

Рекс

mov [x], 1StoreLoadmov r1, [y]

x = 1y = ?

Барьер StoreLoad (≠ StoreStore + LoadLoad):1. Отправка (push) всех изменений в центральный репозиторий.

Центральный репозиторий

154

Page 155: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreLoad

1

Рекс

mov [x], 1StoreLoadmov r1, [y]

x = 1y = ?

Барьер StoreLoad (≠ StoreStore + LoadLoad):1. Отправка (push) всех изменений в центральный репозиторий.

2. Ожидание завершения выполнения операции отправки (в отличие от StoreStore, который может выполняться с задержкой).

Центральный репозиторий

155

Page 156: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьер StoreLoad

1

Рекс

mov [x], 1StoreLoadmov r1, [y]

x = 1y = ?

Барьер StoreLoad (≠ StoreStore + LoadLoad):1. Отправка (push) всех изменений в центральный репозиторий.

2. Ожидание завершения выполнения операции отправки (в отличие от StoreStore, который может выполняться с задержкой).

3. Загрузка (pull) всех последних изменений из центрального репозитория (в отличие от LoadLoad, который не загружает абсолютно последние изменения)

Центральный репозиторий

156

Page 157: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Семантика захват-освобождение (acquire-release semantics)

157

Page 158: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Семантика захвата (acquire)

Семантика захвата и освобождения

▪ Применяется к операциям чтения или чтения-модификации-записи, при этом такая операция становится операцией чтения-захвата (read-acquire).

▪ Предотвращает переупорядочивание инструкции чтения-захвата и всех следующих в программе операций чтения или записи.

▪ Применяется к операциям записи или чтения-модификации-записи, причём такая операция становится операцией записи-освобождения (write-release).

▪ Предотвращает переупорядочивание инструкции записи-освобождения со всеми предшествующими в программе операциями чтения или записи.

Семантика освобождения (release) 158

Page 159: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

read-acquire

Семантика захвата и освобождения

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

write-release 159

Page 160: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

read-acquire

Семантика захвата и освобождения

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

write-release 160

Page 161: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Захват и освобождение - в терминах барьеров

StoreLoadFence StoreStoreFence

LoadStoreFence LoadLoadFence

Acquire (захват)

Release (освобождение)161

Page 162: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

LoadLoadFence + LoadStoreFence

Захват и освобождение - в терминах барьеров

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

StoreStoreFence + LoadStoreFence

read-acquire

write-release 162

Page 163: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

LoadLoadFence + LoadStoreFence

Захват и освобождение - в терминах барьеров

StoreStoreFence + LoadStoreFence

read-acquire

write-release 163

Page 164: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

LoadLoadFence + LoadStoreFence

Захват и освобождение - в терминах барьеров

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

StoreStoreFence + LoadStoreFence

read-acquire

write-release 164

Page 165: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

LoadLoadFence + LoadStoreFence

Захват и освобождение - в терминах барьеров

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

StoreStoreFence + LoadStoreFence

read-acquire

write-release

1

2

165

Page 166: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

LoadLoadFence + LoadStoreFence

Захват и освобождение - в терминах барьеров

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

StoreStoreFence + LoadStoreFence

read-acquire

write-release

2

1

2

1

166

Page 167: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

LoadLoadFence + LoadStoreFence

Захват и освобождение - в терминах барьеров

read / write

read / write

read / write

read / write

read / write

read / write

read / write

read / write

LoadStoreFence + StoreStoreFence

read-acquire

write-release 167

Page 168: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 2

ready.load( memory_order_acquire);

print(x);

Поток 1

x = 42 ready.store(true, memory_order_release);

Семантика захват-освобождение на примере с публикацией

int x;bool ready = false;

168

Page 169: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 1

x = 42 ready.store(true, memory_order_release);

Семантика захват-освобождение на примере с публикацией

Поток 2

ready.load( memory_order_acquire);

print(x);

int x;bool ready = false;

Синхронизируется-с

Synchronizes-with

Всё, что здесь...

… будет видно здесь

169

Page 170: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 1

x = 42 ready.store(true, memory_order_release);

Семантика захват-освобождение на примере с публикацией

Поток 2

ready.load( memory_order_acquire);

print(x);

int x;bool ready = false;

Синхронизируется-с

Synchronizes-with

… будет видно здесь

Всё, что здесь...

Операция записи-освобождения

Операция чтения-захвата

170

Page 171: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Семантика захват-освобождение на примере с публикацией

Поток 1void initWidget(x, y, z) { w.x = x; w.y = x; w.z = z; ready.store(true, memory_order_release);}

Поток 2

void useWidget() { while (!ready.load( memory_order_acquire)) {}

doSomething(w);}

widget w;bool ready = false;

171

Page 172: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 2

void useWidget() { while (!ready.load( memory_order_acquire)) {}

doSomething(w);}

Семантика захват-освобождение на примере с публикацией

Поток 1void initWidget(x, y, z) { w.x = x; w.y = x; w.z = z; ready.store(true, memory_order_release);}

widget w;bool ready = false;

Синхронизируется-с

Synchronizes-with

Всё, что здесь...

… будет видно здесь

Операция записи-освобождения

Операция чтения-захвата

172

Page 173: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 2

void useWidget() { while (!ready.load( memory_order_acquire)) {}

s1 = to_string(w);

s2 = "number " + s1;

print(s2);}

Семантика захват-освобождение на примере с публикацией

int x, y, z;bool ready = false;

Поток 1void initWidget(x, y, z) { x = 10 y = x + 20; z = x + 12; ready.store(true, memory_order_release);}

Синхронизируется-с

Synchronizes-with

173

Page 174: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 2

void useWidget() { while (!ready.load( memory_order_acquire)) {}

s1 = to_string(w);

s2 = "number " + s1;

print(s2);}

Семантика захват-освобождение на примере с публикацией

int x, y, z;bool ready = false;

Поток 1void initWidget(x, y, z) { x = 10 y = x + 20; z = x + 12; ready.store(true, memory_order_release);}

Синхронизируется-с

Synchronizes-with

Операция записи-освобождения

Операция чтения-захвата

174

Page 175: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Захват и освобождение в С++

std::memory_order_acquire

▪ Применяется к операциям чтения или чтения-модификации-записи: load, compare_exchange, fetch_add, fetch_or, etc.▫ x.load(std::memory_order_acquire);

▫ compare_exchange_weak(x, y, std::memory_order_acquire);

▪ Применяется к операциям записи или чтения-модификации-записи: store, operator=, load, compare_exchange, fetch_add, fetch_or, etc▫ x.store(42, std::memory_order_release);

▫ compare_exchange_weak(x, y, std::memory_order_release);

std::memory_order_release 175

Page 176: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение синхронизируется-с (synchronized-with)

176

Page 177: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение synchronized-with (синхронизируется-с)

Отношение syncrhonized-with более сильное по сравнению с happens-before, т.е.:

synchronizes-with ⟶ happens-before

177

Page 178: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение synchronized-with (синхронизируется-с)

Отношение syncrhonized-with более сильное по сравнению с happens-before, т.е.:

synchronizes-with ⟶ happens-before

Операция записи A над переменной x синхронизируется-с такой операцией операцией чтения B над x, которая читает значение, сохранённое

1. или операцией A.

2. или следующей за A операцией записи над x в том же потоке, который выполнил A.

3. или последовательностью операций чтения-модификации-записи над x в любом потоке, при условии, что значение, прочитанное первым потоком в этой последовательности, является значением, записанным операцией A.

178

Page 179: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение synchronized-with (синхронизируется-с)

Отношение syncrhonized-with более сильное по сравнению с happens-before, т.е.:

synchronizes-with ⟶ happens-before

Операция записи A над переменной x синхронизируется-с такой операцией операцией чтения B над x, которая читает значение, сохранённое

1. или операцией A.

2. или следующей за A операцией записи над x в том же потоке, который выполнил A.

3. или последовательностью операций чтения-модификации-записи над x в любом потоке, при условии, что значение, прочитанное первым потоком в этой последовательности, является значением, записанным операцией A.

179

Page 180: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Отношение synchronized-with (синхронизируется-с)

Отношение syncrhonized-with более сильное по сравнению с happens-before, т.е.:

synchronizes-with ⟶ happens-before

Операция записи A над переменной x синхронизируется-с такой операцией операцией чтения B над x, которая читает значение, сохранённое

1. или операцией A.

2. или следующей за A операцией записи над x в том же потоке, который выполнил A.

3. или последовательностью операций чтения-модификации-записи над x в любом потоке, при условии, что значение, прочитанное первым потоком в этой последовательности, является значением, записанным операцией A.

Иначе: Если поток 1 сохраняет значение, а поток 2 читает это значение, то существует отношение синхронизируется-с между операциями сохранения и загрузки. 180

Page 181: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 1void prepare() { w.x = x; w.y = x; cntr++;

w.ready.store(true, memory_order_release);}

Операци Acquire-release (synchronized-with) в С++

Поток 2

void utilize() { while (!w.ready.load( memory_order_acquire)) {}

doSomethingWith(w);

writeLog(cntr);}

Widget w;int cntr;

Синхронизируется-с

Synchronizes-with

181

Page 182: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 1void prepare(Widget &w) { w.x = x; w.y = x; cntr++;

w.ready.store(true, memory_order_release);}

Операци Acquire-release (synchronized-with) в С++

Поток 2

void utilize() { if (!w.ready.load( memory_order_acquire)){

doSomethingWith(w);

writeLog(cntr); }

Widget w;int cntr;

Синхронизируется-с

Synchronizes-with

182

Page 183: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Поток 2void utilize() { bool ready = w.ready.load( memory_order_relaxed); if (ready) { atomic_thread_fence( memory_order_acquire)){

doSomethingWith(w);

writeLog(cntr); }

Поток 1void prepare(Widget &w) { w.x = x; w.y = x; cntr++;

atomic_thread_fence(, memory_order_release);

w.ready.store(true, memory_order_relaxed);}

Барьеры acquire-release (synchronized-with) в С++

Widget w;int cntr;

183

Page 184: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

184

Page 185: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Запись в w, cntr

1

185

Page 186: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Барьер release - все данные загружаются в “репозиторий”Запись в w и

cntr

12

186

Page 187: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Барьер release - все данные загружаются в “репозиторий”Запись в w и

cntr

12

Запись true в ready

3

187

Page 188: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Барьер release - все данные загружаются в “репозиторий”

Мухтар

Центральный репозиторий (ЦР)

Запись в w и cntr

1

ready просачивается в “репозиторий”

2

Запись true в ready

3

4

188

Page 189: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Запись в w и cntr

ready просачивается в “репозиторий”

ready просачивается из ЦР Мухтару

1 Барьер release - все данные загружаются в “репозиторий”

2

Запись true в ready

3

4

5

189

Page 190: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Запись в w и cntr

1 Барьер release - все данные загружаются в “репозиторий”

2

Запись true в ready

3

ready просачивается из ЦР Мухтару

Чтение true в ready

ready просачивается в “репозиторий”

4

56

190

Page 191: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Барьер release - все данные загружаются в “репозиторий”Запись в w и

cntr

12

ready просачивается в “репозиторий”

ready просачивается из ЦР Мухтару

Барьер acquire - данные загружаются из ЦР Мухатору

Запись true в ready

3

4

5

7

Чтение true в ready

6

191

Page 192: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Барьеры acquire-release (synchronized-with) в С++

Рекс

Мухтар

Центральный репозиторий (ЦР)

Запись в w и cntr

Барьер release - все данные загружаются в “репозиторий”

ready просачивается в “репозиторий”

12

Запись true в ready

3

4

ready просачивается из ЦР Мухтару

5

Чтение true в ready

Барьер acquire - данные загружаются из ЦР Мухатору

7Чтение w и cntr

6

8

192

Page 193: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

std::vector<int> queue;std::atomic<int> count;

void pop() { for (auto i = 0; i < num_of_items; i++) queue.push(i); count.store(num_of_items, std::memory_order_release);}

void consume() { for (;;) { auto item_index = count.fetch_sub(1, ?);

if (item_index <= 0) { wait_for_items(); continue; } process(queue[item_index]); }}

Последовательность освобождений

193

Page 194: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операция записи A над переменной x синхронизируется-с такой операцией операцией чтения B над x, которая читает значение, сохранённое

1. или операцией A.

2. или следующей за A операцией записи над x в том же потоке, который выполнил A.

3. или последовательностью операций чтения-модификации-записи над x в любом потоке, при условии, что значение, прочитанное первым потоком в этой последовательности, является значением, записанным операцией A.

Отношение synchronized-with (синхронизируется-с)

194

Page 195: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Операция записи A над переменной x синхронизируется-с такой операцией операцией чтения B над x, которая читает значение, сохранённое

1. или операцией A.

2. или следующей за A операцией записи над x в том же потоке, который выполнил A.

3. или последовательностью операций чтения-модификации-записи над x в любом потоке, при условии, что значение, прочитанное первым потоком в этой последовательности, является значением, записанным операцией A.

Отношение synchronized-with (синхронизируется-с)

195

Если существует последовательность операций чтения-модификации-записи, помеченных признаком acquire, причём каждая операция загрузки загружает значение, записанное предыдущей операцией, то такая цепочка называется последовательностью освобождений.

Операция чтения может быть помечена любым признаком.

Page 196: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

std::vector<int> queue;std::atomic<int> count;

void pop() { for (auto i = 0; i < num_of_items; i++) queue.push(i); count.store(num_of_items, std::memory_order_release);}

void consume() { for (;;) { auto item_index = count.fetch_sub(1, std::memory_order_acquire); if (item_index <= 0) { wait_for_items(); continue; } process(queue[item_index]); }}

Последовательность освобождений

196

Page 197: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Последовательность освобождений

197

pop() {

for (...) { queue.push(...) }

count.store( release)

consume() { ... count.fetch_sub( acquire)

process(...)

consume() { ... count.fetch_sub( acquire)

process(...)

T1 T2 T3

10

9

8

синхронизируется-сцепочка зависимостейпроисходит раньше

Page 198: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Связь семантики захвата-освобождения с проблемой взаимного исключения или что же такое мьютекс?

198

Page 199: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

class spinlock_mutex { std::atomic_flag flag;

public: spinlock_mutex(): flag{ATOMIC_FLAG_INIT} { }

void lock() { while (flag.test_and_set( std::memory_order_acquire)); }

void unlock() { flag.clear(std::memory_order_release); }};

Реализация спинлока на основе атомарного флага

199

Page 200: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

class spinlock_mutex { std::atomic_flag flag;

public: spinlock_mutex(): flag{ATOMIC_FLAG_INIT} { }

void lock() { while (flag.test_and_set( std::memory_order_acquire)); }

void unlock() { flag.clear(std::memory_order_release); }};

Реализация спинлока на основе атомарного флага

Операция записи-освобождения

Операция чтения-захвата

200

Page 201: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

...mut.lock(); // Ay = 2; // Bmut.unlock();...

Мьютекс и семантика захвата-освобождения

Что всё-таки подразумевается под переупорядочиванием инструкций (A и В) в потоке?

T1

Это означает, что есть какой-то второй поток, который “видит” эти операции, выполняющиеся в другом порядке.

201

Page 202: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

...mut.lock(); y = 2; mut.unlock();...

Мьютекс и семантика захвата-освобождения

Что всё-таки подразумевается под переупорядочиванием инструкций (A и В) в потоке?

T1 T2

2

1

Это означает, что есть какой-то второй поток, который “видит” эти операции, выполняющиеся в другом порядке.

202

Page 203: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

Что всё-таки подразумевается под переупорядочиванием инструкций (A и В) в потоке?

T1

Это означает, что есть какой-то второй поток, который “видит” эти операции, выполняющиеся в другом порядке.

T2

...mut.lock(); y *= 10; mut.unlock();...

...mut.lock(); y = 2; mut.unlock();...

203

Page 204: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

Что всё-таки подразумевается под переупорядочиванием инструкций (A и В) в потоке?

Это означает, что есть какой-то второй поток, который “видит” эти операции, выполняющиеся в другом порядке.

...mut.lock(); mut.unlock();y = 2; ...

T1 T2

...mut.lock(); y *= 10; mut.unlock();...

гонка!

204

Page 205: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

x = 1;mut.lock();y = 2;mut.unlock();z = 3;

Мьютекс и семантика захвата-освобождения

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

Можно трансформировать это в это?

205

Page 206: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

x = 1;mut.lock();y = 2;mut.unlock();z = 3;

Мьютекс и семантика захвата-освобождения

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

Можно трансформировать это в это?

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

x = 1;mut.lock();y = 2;mut.unlock();z = 3;

в это?а это

206

Page 207: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

x = 1;mut.lock();y = 2;mut.unlock();z = 3;

Мьютекс и семантика захвата-освобождения

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

Можно трансформировать это в это?

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

x = 1; // гонка!mut.lock();y = 2;mut.unlock();z = 3; // гонка!

в это?а это

207

Page 208: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

... void lock() { while (flag.test_and_set( std::memory_order_relaxed)); } void unlock() { flag.clear(std::memory_order_relaxed); }

Мьютекс и семантика захвата-освобождения

Допустим

208

Page 209: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

... void lock() { while (flag.test_and_set( std::memory_order_relaxed)); } void unlock() { flag.clear(std::memory_order_relaxed); }

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

Мьютекс и семантика захвата-освобождения

Допустим

Но тогда

x = 1;mut.lock();y = 2;mut.unlock();z = 3;

209

Page 210: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

... void lock() { while (flag.test_and_set( std::memory_order_relaxed)); } void unlock() { flag.clear(std::memory_order_relaxed); }

Но тогда

mut.lock();x = 1;y = 2;z = 3;mut.unlock();

Мьютекс и семантика захвата-освобождения

x = 1;mut.lock();y = 2;mut.unlock();z = 3;

Допустим

210

Page 211: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

k = 1;l = 2;

mut.lock();

x = 3;y = 4;z = 5;

mut.unlock();

p = 6;q = 7;

211

Page 212: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

k = 1;l = 2;

mut.lock();

x = 3;y = 4;z = 5;

mut.unlock();

p = 6;q = 7;

flag.clear(std::memory_order_release)

flag.test_and_set( std::memory_order_acquire)

212

Page 213: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

acquire

release

Мьютекс и семантика захвата-освобождения

k = 1;l = 2;

mut.lock();

x = 3;y = 4;z = 5;

mut.unlock();

p = 6;q = 7;

Мьютекс определяет семантику захвата-освобождения (lock - запись-освобождение, release - чтение-захват):

mutex ⟶ acquire-release

flag.clear(std::memory_order_release)

flag.test_and_set( std::memory_order_acquire)

213

Page 214: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

acquire

release

Мьютекс и семантика захвата-освобождения

k = 1;l = 2;

mut.lock();

x = 3;y = 4;z = 5;

mut.unlock();

p = 6;q = 7;

Мьютекс определяет семантику захвата-освобождения (lock - запись-освобождение, release - чтение-захват):

mutex ⟶ acquire-releaseЯвляется ли пара операций захвата-освобождения достаточной для реализации взаимного исключения

acquire-release ⟶ mutex ??

flag.clear(std::memory_order_release)

flag.test_and_set( std::memory_order_acquire)

214

Page 215: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

...mut.lock();y = 2;mut.unlock();...

Мьютекс и семантика захвата-освобождения

...mut.lock();y *= 10;mut.unlock();...

...mut.lock();y += 22;mut.unlock();...

T1 T2 T3

215

Page 216: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

flag.load() // 0...y = 2;...flag.store(0)...

Мьютекс и семантика захвата-освобождения

flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 0...y += 22;...flag.store(0)

flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 0...y *= 10;...flag.store(0);

T1 T3T2

216

Page 217: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

T1 T3T2

load-acquire...y = 2;...store-release...

flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1load-acquire...y += 22;...store-release

flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1flag.load() // 1load-acquire...y *= 10;...store-release

217

Synchronizes-with

Синхронизируется-с

Synchronizes-with

Синхронизируется-с

Page 218: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

T1 T3T2

load-acquire...y += 22;...store-release

load-acquire...y *= 10;...store-release

Synchronizes-with

Синхронизируется-с

Synchronizes-with

Синхронизируется-с218

load-acquire...y = 2;...store-release...

Page 219: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Мьютекс и семантика захвата-освобождения

T1 T3T2

load-acquire...y = 2;...store-release...

load-acquire...y += 22;...store-release

load-acquire...y *= 10;...store-release

Synchronizes-with

Синхронизируется-с

Synchronizes-with

Синхронизируется-с219

Пара загрузки-сохранения (load-store) обеспечивает взаимное исключение в том и только в том случае, если загрузка является операцией захвата (acquire), а сохранение - операцией освобождения (release), и если операция загрузки синхронизируется-с (synchronized-with) операцией сохранения предыдущей пары загрузки-сохранения, а операция сохранения синхронизируется с операцией сохранения последующей пары загрузки сохранения.

Page 220: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Решение проблемый двойной проверки с помощью модели памяти С++

220

Page 221: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Проблема двойной проверки

221

Widget* Widget::instance_ptr{nullptr};

Widget* Widget::instance() {

if (instance_ptr == nullptr) { // 1: 1 проверка lock_guard<mutex> lock{mut}; // 2: запираем

if (instance_ptr == nullptr) { // 3: 2 проверка instance_ptr = new Widget(); // 4: создать // и присвоить } } // 5: отпираем return instance_ptr; // 6: возвращаем}

Основная проблема: гонка данных между операциями 1 и 4.

Она может привести, например, к частичной инициализации instance_ptr

Page 222: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Проблема двойной проверки

222

std::atomic<Widget*> Widget::instance_ptr{nullptr};

Widget* Widget::instance() {

if (instance_ptr == nullptr) { // 1: 1 проверка lock_guard<mutex> lock{mut}; // 2: запираем

if (instance_ptr == nullptr) { // 3: 2 проверка instance_ptr = new Widget(); // 4: создать // и присвоить } } // 5: отпираем return instance_ptr; // 6: возвращаем}

Page 223: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Проблема двойной проверки

223

std::atomic<Widget*> Widget::instance_ptr{nullptr};

Widget* Widget::instance() {

if (instance_ptr == nullptr) { lock_guard<mutex> lock{mut};

if (instance_ptr == nullptr) { instance_ptr = new Widget(); } } return instance_ptr; }

нужен барьер

нужен барьер

Page 224: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Проблема двойной проверки в С++

224

std::atomic<Widget*> Widget::instance_ptr{nullptr};

Widget* Widget::instance() { Widget* tmp = instance_ptr.load(memory_order_relaxed); atomic_thread_fence(memory_order_acquire);

if (tmp == nullptr) { lock_guard<mutex> lock{mut}; tmp = instance_ptr.load(memory_order_relaxed);

if (tmp == nullptr) { instance_ptr = new Widget();

atomic_thread_fence(memory_order_release); instance_ptr.store(tmp, memory_order_relaxed); } } return tmp; }

Page 225: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

Проблема двойной проверки в С++

225

std::atomic<Widget*> Widget::instance_ptr{nullptr};

Widget* Widget::instance() {

if (instance_ptr.load(memory_order_acquire) == nullptr) {

lock_guard<mutex> lock{mut}; tmp = instance_ptr.load(memory_order_relaxed);

if (tmp == nullptr) { instance_ptr = new Widget();

instance_ptr.store(tmp, memory_order_release); } } return tmp; }

Page 226: ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инструкций. Барьеры памяти. Атомарные

instance_ptr = new Widget();

instance_ptr.store(tmp, memory_order_release);}

Мьютекс и семантика захвата-освобождения

if (instance_ptr.load(memory_order_acquire) == nullptr) {

lock_guard<mutex> lock{mut};

tmp = instance_ptr.load( memory_order_relaxed);

if (tmp == nullptr) {

T1 T2

226

всё здесь

видно здесь

Synchronizes-with

Синхронизируется-с