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

1 встреча — Параллельное программирование (А. Свириденков)

1 встреча — Параллельное программирование (А. Свириденков)

2 встреча Smolensk Computer Science Club
Анатолий Свириденков про параллельное программирование
ВКонтакте: http://vk.com/scsc1

Smolensk Computer Science Club

September 21, 2012
Tweet

More Decks by Smolensk Computer Science Club

Other Decks in Programming

Transcript

  1. План  Введение в параллелизм  Примитивы синхронизации (теория) 

    Проблемы многопоточности (практика)  Алгоритмы и структуры данных
  2. Классификация Флина  SISD (Single Instruction Single Data) – классический

    процессор старой школы  SIMD (Single Instruction Multiple Data) – MMX, SSE  MISD (Multiple Instruction Single Data) – до конца не определено  MIMD (Multiple Instruction Multiple Data) – многоядерные процессоры  SIMT (Single Instruction Multiple Threads) – кастыли от NVIDIA
  3. Неочевидный параллелизм  Много потоков на одном ядре (квазимногопоточность) 

    Аппаратное ускорение: сопроцессоры, DMA, аппаратные прерывания.  Кластеры  Интернет
  4. Мьютекс  Mutex (mutual execution) – примитив исключающий совместный доступ

    к разделяемому ресурсу. Семафор Дейкстры (1965): P: while (s==0) sleep; // вход s = s — 1; V: s = s + 1; // выход
  5. Алгоритм Петерсона (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
  6. Событие  События служат для информирования потоко о событии. 

    Типичное применение событий: Производитель – Потребитель (Producer – Consumer)  События нельзя применять для синхронизации доступа.
  7. Возможно ли r1 = r2 = 0 ? Поток 1:

    x = 1 r1 = y; Поток 2: y = 1; r2 = x; int x = 0; int y = 0; int r1 = -1; int r2 = -1;
  8. volatile  volatile – ключевое слово для работы с signals.

    Запрещает перемещение переменной в регистр.  volatile – модификатор доступа, как и const. Могут быть volatile классы и функции. Снимается через const_cast<>;  MS specific – к volatile атомарный доступ
  9. Что тут в r1 и r2? Поток 1: x =

    -1 r1 = y; Поток 2: y = -1; r2 = x; volatile int x = 0; volatile int y = 0; int r1 = 0; int r2 = 0;
  10. Гонки и атомарный доступ char * buffer[3] = {0} 

    Поток 1: strcpy(buffer, ”11”);  Поток 2: strcpy(buffer, ”22”); Итог: 11, 12, 21, 22
  11. Атомарность в x86  BYTE;  WORD, DWORD выровненые на

    границу кеш линии;  WORD, DWORD с сигналом LOCK на шине. В С\С++ функции InterlockedXXXX.
  12. Если все атомарно (r1 = r2 = 0)? Поток 1:

    x = 1 r1 = y; Поток 2: y = 1; r2 = x; volatile int x = 0; volatile int y = 0; int r1 = -1; int r2 = -1;
  13. Конфликты в конвеере  Конфликты по данным – ввод одной

    инструкции зависит от вывода другой;  Конфликты по управлению – переходы;  Структурный конфликт – нехватка вычислительных модулей (ALU).
  14. Модели памяти  Строгая модель памяти – out-of-order выполнение запрещено;

     Слабая модель позволяет переупорядычивание операций; Intel® 64 Architecture Memory Ordering White Paper Foundations of the C++ Concurrency Memory Model
  15. Барьеры памяти  lfence — все операции загрузки должны быть

    заверены пока команда выполняется;  sfence — все операции выгрузки должны быть заверешны пока команда выполняется;  mfence — sfence + lfence;  cpuid;  interlocked операции.
  16. Memory Ordering in Modern Microprocessors Type Alpha ARMv7 POWER x86

    x86 oostore AMD64 IA64 Loads reordered after Loads y y y y y Loads reordered after Stores y y y y y Stores reordered after Stores y y y y y Stores reordered after Loads y y y y y y y Atomic reordered with Loads y y y y Atomic reordered with Stores y y y y Dependent Loads reordered y Incoherent Instruction cache pipeline y y y y y y
  17. Как должно быть Поток 1: x = 1 mfence; r1

    = y; Поток 2: y = 1; mfence; r2 = x; volatile int x = 0; volatile int y = 0; int r1 = -1; int r2 = -1;
  18. Deadlock detection struct RTL_CRITICAL_SECTION { PRTL_CRITICAL_SECTION_DEBUG DebugInfo; LONG LockCount; LONG

    RecursionCount; HANDLE OwningThread; HANDLE LockSemaphore; ULONG_PTR SpinCount; };
  19. Deadlock detection struct _RTL_CRITICAL_SECTION_DEBUG { WORD Type; WORD CreatorBackTraceIndex; RTL_CRITICAL_SECTION

    *CriticalSection; LIST_ENTRY ProcessLocksList; DWORD EntryCount; DWORD ContentionCount; DWORD Spare[ 2 ]; }
  20. Пересинхронизация на общем ресурсе for(int i = 0; i <

    SIZE/2; i++) { EnterCriticalSectio(&cs); sum += array[i]; LeaveCriticalSection(&cs); } for(int i = 0; i < SIZE/2; i++) { EnterCriticalSectio(&cs); sum += array[i + SIZE/2]; LeaveCriticalSection(&cs); } int sum = 0; int array[SIZE]; CRITICAL_SECTION cs;
  21. Пересинхронизация и кеш for(int i = 0; i < SIZE/2;

    i++) { array[2*i] = i; } for(int i = 0; i < SIZE/2; i++) { array[2*i + 1] = i; } int array[SIZE] = {0};
  22. Принципы на примере циклов Не распараллеленый: C[i] = A[i] +

    B[i]; Распараллеленый C[N*i + k] = A[N*i + k] + B[N*i + k]  N – количество потоков  k – номер потока
  23. Зависимость назад Не распараллеленый: A[i - 1] = A[i] +

    B[i]; Распараллеленый AN = A A[N*i + k - 1] = AN[N*i + k] + B[N*i + k]  N – количество потоков  k – номер потока
  24. Зависимость вперед Не распараллеленый: A[i + 1] = A[i] +

    B[i]; Распараллеленый В общем случае не параллелится.
  25. Данные и алгоритмы  Блокировки – с явной синхронизацией; 

    Obstruction-free (без препятствий) – поток завершит исполнение за детерменированное количество шагов;  Lock-free (без блокировок) – на каждом шаге происходит прогресс в системе;  Wait-free (без ожиданий) – нет ожиданий.