10. Мьютекс
Mutex (mutual execution) – примитив
исключающий совместный доступ к
разделяемому ресурсу.
Семафор Дейкстры (1965):
P: while (s==0) sleep; // вход
s = s — 1;
V: s = s + 1; // выход
11. Алгоритм Петерсона (1981)
shared int[2] = {0, 0};
shared int turn;
// вход в cs
ready[i] = 1; // i — номер потока
turn = 1 — i;
while(ready[1 — i] && turn == 1-i);
// cs
ready[i] = 0; // выход из cs
12. Событие
События служат для информирования
потоко о событии.
Типичное применение событий:
Производитель – Потребитель (Producer –
Consumer)
События нельзя применять для
синхронизации доступа.
15. Возможно ли r1 = r2 = 0 ?
int x = 0;
int y = 0;
int r1 = -1;
int r2 = -1;
Поток 1: Поток 2:
x=1 y = 1;
r1 = y; r2 = x;
16. volatile
volatile – ключевое слово для работы с
signals. Запрещает перемещение
переменной в регистр.
volatile – модификатор доступа, как и const.
Могут быть volatile классы и функции.
Снимается через const_cast<>;
MS specific – к volatile атомарный доступ
17. Что тут в r1 и r2?
volatile int x = 0;
volatile int y = 0;
int r1 = 0;
int r2 = 0;
Поток 1: Поток 2:
x = -1 y = -1;
r1 = y; r2 = x;
18. Гонки и атомарный доступ
char * buffer[3] = {0}
Поток 1: strcpy(buffer, ”11”);
Поток 2: strcpy(buffer, ”22”);
Итог: 11, 12, 21, 22
19. Атомарность в x86
BYTE;
WORD, DWORD выровненые на границу кеш
линии;
WORD, DWORD с сигналом LOCK на шине.
В СС++ функции InterlockedXXXX.
20. Если все атомарно (r1 = r2 = 0)?
volatile int x = 0;
volatile int y = 0;
int r1 = -1;
int r2 = -1;
Поток 1: Поток 2:
x=1 y = 1;
r1 = y; r2 = x;
23. Без конвеера
Такт Выборка Декод. Выполнение Запись
1 К1
2 К1
3 К1
4 К1
24. С конвеером
Такт Выборка Декод. Выполнение Запись
1 К1
2 К2 К1
3 К3 К2 К1
4 К4 К3 К2 К1
25. Конфликты в конвеере
Конфликты по данным – ввод одной
инструкции зависит от вывода другой;
Конфликты по управлению – переходы;
Структурный конфликт – нехватка
вычислительных модулей (ALU).
26. Модели памяти
Строгая модель памяти – out-of-order
выполнение запрещено;
Слабая модель позволяет
переупорядычивание операций;
Intel® 64 Architecture Memory Ordering White Paper
Foundations of the C++ Concurrency Memory Model
27. Барьеры памяти
lfence — все операции загрузки должны
быть заверены пока команда
выполняется;
sfence — все операции выгрузки
должны быть заверешны пока команда
выполняется;
mfence — sfence + lfence;
cpuid;
interlocked операции.
28. Memory Ordering in Modern Microprocessors
Type Alpha ARMv7 POWER x86 x86 AMD64 IA64
oostore
Loads reordered y y y y y
after Loads
Loads reordered y y y y y
after Stores
Stores reordered y y y y y
after Stores
Stores reordered y y y y y y y
after Loads
Atomic reordered y y y y
with Loads
Atomic reordered y y y y
with Stores
Dependent Loads y
reordered
Incoherent y y y y y y
Instruction cache
pipeline
29. Как должно быть
volatile int x = 0;
volatile int y = 0;
int r1 = -1;
int r2 = -1;
Поток 1: Поток 2:
x=1 y = 1;
mfence; mfence;
r1 = y; r2 = x;
35. Пересинхронизация на общем ресурсе
int sum = 0;
int array[SIZE];
CRITICAL_SECTION cs;
for(int i = 0; i < SIZE/2; i++) for(int i = 0; i < SIZE/2; i++)
{ {
EnterCriticalSectio(&cs); EnterCriticalSectio(&cs);
sum += array[i]; sum += array[i + SIZE/2];
LeaveCriticalSection(&cs); LeaveCriticalSection(&cs);
} }
36. Пересинхронизация и кеш
int array[SIZE] = {0};
for(int i = 0; i < SIZE/2; i++) for(int i = 0; i < SIZE/2; i++)
{ {
array[2*i] = i; array[2*i + 1] = i;
}
}
37. Принципы на примере циклов
Не распараллеленый:
C[i] = A[i] + B[i];
Распараллеленый
C[N*i + k] = A[N*i + k] + B[N*i + k]
N – количество потоков
k – номер потока
38. Зависимость назад
Не распараллеленый:
A[i - 1] = A[i] + B[i];
Распараллеленый
AN = A
A[N*i + k - 1] = AN[N*i + k] + B[N*i + k]
N – количество потоков
k – номер потока
39. Зависимость вперед
Не распараллеленый:
A[i + 1] = A[i] + B[i];
Распараллеленый
В общем случае не параллелится.
40. Некоторые приемы
Пул потоков
Асинхронное программирования
Двойная проверка
Map reduce
Счетчик доступа
41. Данные и алгоритмы
Блокировки – с явной синхронизацией;
Obstruction-free (без препятствий) – поток
завершит исполнение за
детерменированное количество шагов;
Lock-free (без блокировок) – на каждом шаге
происходит прогресс в системе;
Wait-free (без ожиданий) – нет ожиданий.
42. Приемы
Read-only
Атомарные операции
Барьеры памяти