SlideShare ist ein Scribd-Unternehmen logo
1 von 85
Downloaden Sie, um offline zu lesen
Лекция 7:
Многопоточное программирование
Часть 3
(Multithreading programming)
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
Программный инструментарий
Прикладные библиотеки






Intel Threading Building Blocks (TBB)
Microsoft Concurrency Runtime
Apple Grand Central Dispatch
Boost Threads
Qthread, MassiveThreads

Языки программирования
 OpenMP
(C/C++/Fortran)
 Intel Cilk Plus
 С++11 Threads
 C11 Threads






C# Threads
Java Threads
Erlang Threads
Haskell Threads

Системные библиотеки (System libraries)

Уровень
пользователя
(User space)

GNU/Linux Pthreads
Thread

Thread

Уровень ядра
(Kernel space)

Win32 API/.NET Threads
Thread

Thread

Thread

Apple OS X Cocoa, Pthreads
Thread

Thread

…

Thread

Kernel
thread

…

Kernel
thread

Системные вызовы (System calls)
Kernel
thread

Kernel
thread

Kernel
thread

Kernel
thread

Kernel
thread

Kernel
thread

Process/thread scheduler

Операционная система (Operating System)
GNU/Linux, Microsoft Windows, Apple OS X, IBM AIX, Oracle Solaris, …
Hardware (Multi-core processors, SMP/NUMA)

2
Стандарт OpenMP
 OpenMP (Open Multi-Processing) – стандарт, определяющий набор
директив компилятора, библиотечных процедур и переменных среды
окружения для создания многопоточных программ
 Текущая версия стандарта – OpenMP 4.0
 Требуется поддержка со стороны компилятора

www.openmp.org

3
OpenMP
Compiler

Information

GNU GCC

Option: –fopenmp
gcc 4.2 – OpenMP 2.5,
gcc 4.4 – OpenMP 3.0,
gcc 4.7 – OpenMP 3.1
gcc 4.9 – OpenMP 4.0

Clang (LLVM)

OpenMP 3.1
Clang + Intel OpenMP RTL
http://clang-omp.github.io/

Intel C/C++, Fortran

OpenMP 3.1
Option: –Qopenmp, –openmp

Oracle Solaris Studio
C/C++/Fortran

OpenMP 3.1
Option: –xopenmp

Microsoft Visual Studio 2012 C++

Option: /openmp
OpenMP 2.0 only

Other compilers: IBM XL, PathScale, PGI, Absoft Pro, …
http://openmp.org/wp/openmp-compilers/

4
Структура OpenMP-программы
 Программа представляется в виде
последовательных участков кода (serial code)
и параллельных регионов (parallel region)

 Каждый поток имеет номер: 0, 1, 2, …

0

0

1

2

 Главный поток (master) имеет номер 0

 Память процесса (heap) является
общей для всех потоков

Барьерная
синхронизация

 OpenMP реализует динамическое управление
потоками (task parallelism)
 OpenMP: data parallelism + task parallelism

0

0

1

5
Пример OpenMP-программы
#include <omp.h>
int main()
{
#pragma omp parallel
{
printf("Thread %dn", omp_get_thread_num());
}
return 0;
}

6
Компиляция OpenMP-программы
$ gcc –fopenmp –o prog ./prog.c
$ ./prog
Thread 0
Thread 1
Thread 3
Thread 2

$ export OMP_NUM_THREADS=2
$ ./prog
Thread 0
Thread 1

По умолчанию количество потоков = количеству
логических процессоров в системе

7
Пример OpenMP-программы
#include <omp.h>
int main()
{

#pragma omp parallel
{
#ifdef _OPENMP
printf("Thread %dn", omp_get_thread_num());
#endif
}
return 0;
}

8
Директивы OpenMP
#pragma omp <директива> [раздел [ [,] раздел]...]

 Создание потоков
 Распределение вычислений между потоками
 Управление пространством видимости переменных

 Механизмы синхронизации потоков
 …

9
Создание потоков (parallel)
#pragma omp parallel
{
/* Этот код выполняется всеми потоками */
}
#pragma omp parallel if (expr)
{
/* Код выполняется потоками если expr = true */
}
#pragma omp parallel num_threads(n / 2)
{
/* Создается n / 2 потоков */
}

На выходе из параллельного региона осуществляется барьерная
синхронизация – все потоки ждут последнего
10
Создание потоков (sections)
#pragma omp parallel sections
{
#pragma omp section
{
/* Код потока 0 */
}
#pragma omp section
{
/* Код потока 1 */
}
}

При любых условиях выполняется фиксированное
количество потоков (по количеству секций)
11
Функции runtime-библиотеки
 int omp_get_thread_num() – возвращает номер текущего
потока
 int omp_get_num_threads() – возвращает количество
потоков в параллельном регионе
 void omp_set_num_threads(int n)

 double omp_get_wtime()

12
Директива master
#pragma omp parallel
{
/* Этот код выполняется всеми потоками */
#pragma omp master
{
/* Код выполняется только потоком 0 */
}
/* Этот код выполняется всеми потоками */
}

13
Директива single
#pragma omp parallel
{
/* Этот код выполняется всеми потоками */
#pragma omp single
{
/* Код выполняется только одним потоком */
}
/* Этот код выполняется всеми потоками */
}

14
Директива for (data parallelism)
#define N 13
#pragma omp parallel
{
#pragma omp for
for (i = 0; i < N; i++) {
printf("Thread %d i = %dn",
omp_get_thread_num(), i);
}
}

Итерации цикла распределяются между потоками

i:

0

1

2

Thread 0

3

4

5

Thread 1

6

7

8

Thread 2

9

10

11

12

Thread 3
15
Директива for
$ OMP_NUM_THREADS=4 ./prog
Thread 2 i = 7
Thread 2 i = 8
Thread 2 i = 9
Thread 0 i = 0
Thread 0 i = 1
Thread 0 i = 2
Thread 3 i = 10
Thread 3 i = 11
Thread 3 i = 12
Thread 0 i = 3
Thread 1 i = 4
Thread 1 i = 5
Thread 1 i = 6
16
Алгоритмы распределения итераций
#define N 13
#pragma omp parallel
{
#pragma omp for schedule(static, 2)
for (i = 0; i < N; i++) {
printf("Thread %d i = %dn",
omp_get_thread_num(), i);
}
}
Итерации цикла распределяются циклически (round-robin)
блоками по 2 итерации

i:

0

1

T0

2

3

T1

4

5

T2

6

7

T3

8

9

T0

10

11

T1

12
T2
17
Алгоритмы распределения итераций
$ OMP_NUM_THREADS=4 ./prog
Thread 0 i = 0
Thread 0 i = 1
Thread 0 i = 8
Thread 0 i = 9
Thread 1 i = 2
Thread 1 i = 3
Thread 1 i = 10
Thread 1 i = 11
Thread 3 i = 6
Thread 3 i = 7
Thread 2 i = 4
Thread 2 i = 5
Thread 2 i = 12
18
Алгоритмы распределения итераций
Алгоритм
static, m

Описание
Цикл делится на блоки по m итераций
(до выполнения), которые распределяются
по потокам

Цикл делится на блоки по m итераций.
dynamic, m При выполнении блока из m итераций поток
выбирает следующий блок из общего пула
guided, m

runtime

Блоки выделяются динамически. При каждом
запросе размер блока уменьшается
экспоненциально до m
Алгоритм задается пользователем через
переменную среды OMP_SCHEDULE
19
Директива for (ordered)
#define N 7
#pragma omp parallel
{
#pragma omp for ordered
for (i = 0; i < N; i++) {
#pragma omp ordered
printf("Thread %d i = %dn",
omp_get_thread_num(), i);
}
}



Директива ordered организует последовательное
выполнение итераций (i = 0, 1, …) – синхронизация



Поток с i = k ожидает пока потоки с i = k – 1, k – 2, …
не выполнят свои итерации
20
Директива for (ordered)
$ OMP_NUM_THREADS=4 ./prog
Thread 0 i = 0
Thread 0 i = 1
Thread 1 i = 2
Thread 1 i = 3
Thread 2 i = 4
Thread 2 i = 5
Thread 3 i = 6

21
Директива for (nowait)
#define N 7
#pragma omp parallel
{
#pragma omp for nowait
for (i = 0; i < N; i++) {
printf("Thread %d i = %dn",
omp_get_thread_num(), i);
}
}



По окончанию цикла потоки не выполняют
барьерную синхронизацию



Конструкция nowait применима и к директиве sections
22
Директива for (collapse)
#define N 3
#define M 4
#pragma omp parallel
{
#pragma omp for collapse(2)
for (i = 0; i < N; i++) {
for (j = 0; j < M; j++)
printf("Thread %d i = %dn",
omp_get_thread_num(), i);
}
}

 сollapse(n) объединяет пространство итераций n циклов в одно
i: 0
0,0

1
0,1

T0

+

2
0,2

j: 0

0,3

1,0

T1

1
1,1

2

3

1,2

1,3

T2

2,0

2,1

2,2

T3

2,3

23
Директива for (collapse)
$ OMP_NUM_THREADS=4 ./prog
Thread 2 i = 1
Thread 2 i = 1
Thread 2 i = 2
Thread 0 i = 0
Thread 0 i = 0
Thread 0 i = 0
Thread 3 i = 2
Thread 3 i = 2
Thread 3 i = 2
Thread 1 i = 0
Thread 1 i = 1
Thread 1 i = 1

24
Ошибки в многопоточных программах
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec(1000);

std::fill(vec.begin(), vec.end(), 1);
int counter = 0;
#pragma omp parallel for
for (std::vector<int>::size_type i = 0;
i < vec.size(); i++)
{
if (vec[i] > 0) {
counter++;
}
}
std::cout << "Counter = " << counter << std::endl;
return 0;
}

25
Ошибки в многопоточных программах
$ g++ –fopenmp –o ompprog ./ompprog.cpp
$ ./omprog
Counter = 381
$ ./omprog
Counter = 909
$ ./omprog
Counter = 398

На каждом запуске итоговое значение Counter разное!
Правильный результат Counter = 1000
26
Ошибки в многопоточных программах
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec(1000);

Потоки осуществляют конкурентный
std::fill(vec.begin(), vec.end(), 1);
int counter = 0;
доступ к переменной counter –
одновременно читают её и записывают

#pragma omp parallel for
for (std::vector<int>::size_type i = 0;
i < vec.size(); i++)
{
if (vec[i] > 0) {
counter++;
}
}
std::cout << "Counter = " << counter << std::endl;
return 0;
}

27
Состояние гонки (Race condition, data race)
#pragma omp parallel
{
counter++;
}

movl [counter], %eax
incl %eax
movl %eax, [counter]

C++

Идеальная последовательность выполнения инструкций 2-х потоков
Thread 0

Memory
(counter)

Thread 1

0
movl [counter], %eax

←

0
0

incl %eax
→

movl %eax, [counter]
movl [counter], %eax

1

←

1
1

incl %eax
movl %eax, [counter]
counter = 2

→

2

28
Состояние гонки (Race condition, data race)
#pragma omp parallel
{
counter++;
}

movl [counter], %eax
incl %eax
movl %eax, [counter]

C++

Возможная последовательность выполнения инструкций 2-х потоков
Thread 0

Memory
(counter)

Thread 1

0
←

movl [counter], %eax

0

incl %eax

movl [counter], %eax

←

0

movl %eax, [counter]

incl %eax

→

1

movl %eax, [counter]

→

1
1

Error: Data race
counter = 1

29
Состояние гонки (Race condition, data race)
 Состояние гонки (Race condition, data race) –
это состояние программы, в которой несколько потоков
одновременно конкурируют за доступ к общей структуре
данных (для чтения/записи)
 Порядок выполнения потоков заранее не известен –
носит случайный характер
 Планировщик динамически распределяет процессорное время
учитывая текущую загруженность процессорных ядер,
а нагрузку (потоки, процессы) создают пользователи, поведение
которых носит случайных характер
 Состояние гонки данных (Race condition, data race) трудно
обнаруживается в программах и воспроизводится в тестах
 Состояние гонки данных (Race condition, data race) –
это типичный пример Гейзенбага (Heisenbug)

30
Обнаружение состояния гонки (Data race)
Динамические анализаторы
 Valgrind Helgrind, DRD
 Intel Thread Checker
 Oracle Studio Thread Analyzer

 Java ThreadSanitizer
 Java Chord
Статические анализаторы кода
 PVS-Studio (viva64)
 …

31
Valgrind Helgrind
$ g++ -fopenmp -o ompprog ./ompprog.cpp
$ valgrind --helgrind ./ompprog
==8238==
==8238==
==8238==
==8238==
...
==8266==

Helgrind, a thread error detector
Copyright (C) 2007-2012, and GNU GPL'd, by OpenWorks LLP et al.
Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
Command: ./ompprog report
----------------------------------------------------------------

==8266== Possible data race during write of size 4 at 0x7FEFFD358 by thread #3
==8266== Locks held: none
==8266==
at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14)
==8266==
by 0x3F84A08389: ??? (in /usr/lib64/libgomp.so.1.0.0)
==8266==
by 0x4A0A245: ??? (in /usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so)
==8266==
by 0x34CFA07C52: start_thread (in /usr/lib64/libpthread-2.17.so)
==8266==
by 0x34CF2F5E1C: clone (in /usr/lib64/libc-2.17.so)
==8266==
==8266== This conflicts with a previous write of size 4 by thread #1
==8266== Locks held: none
==8266==
==8266==

at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14)
by 0x400CE8: main (ompprog.cpp:11)...

32
Директивы синхронизации


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



#pragma omp critical



#pragma omp atomic



#pragma omp ordered



#pragma omp barrier

33
Критические секции
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp critical
{
sum += v;
}
}

34
Критические секции
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp critical
{
sum += v;
}
}

 Критическая секция (Critical section) – участок кода
в многопоточной программе, выполняемый всеми
потоками последовательно

 Критические секции снижают степень параллелизма

35
Управление видимостью переменных
 private(list) – во всех потоках создаются локальные копии
переменных (начальное значение)
 firstprivate(list) – во всех потоках создаются локальные
копии переменных, которые инициализируются их
значениями до входа в параллельный регион
 lastprivate(list) – во всех потоках создаются локальные
копии переменных. По окончанию работы всех потоков
локальная переменная вне параллельного региона
обновляется значением этой переменной одного из
потоков

 shared(list) – переменные являются общими для всех
потоков
36
Атомарные операции
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp atomic
sum += v;
}

37
Атомарные операции
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp atomic
sum += v;
}

 Атомарные операции “легче” критических секций
(не используют блокировки)
 Lock-free algorithms & data structures
38
Параллельная редукция
#pragma omp parallel for reduction(+:sum)
for (i = 0; i < n; i++) {
sum = sum + fun(a[i]);
}

 Операции директивы reduction:

+, *, -, &, |, ^, &&, ||, max, min
 OpenMP 4.0 поддерживает пользовательские
функции редукции

39
Директивы синхронизации
#pragma omp
{
/* Code
#pragma
/* Code
}

parallel

*/
omp barrier
*/

 Директива barrier осуществляет ожидание достижения
данной точки программы всеми потоками

40
#pragma omp flush
#pragma omp
{
/* Code
#pragma
/* Code
}

parallel
*/
omp flush(a, b)
*/



Принудительно обновляет в памяти значения
переменных (Memory barrier)



Например, в одном потоке выставляем флаг
(сигнал к действию) для другого
41
Умножение матриц v1.0
#pragma omp parallel
{
#pragma omp for
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
for (k = 0; k < N; k++) {
c[i][j] = c[i][j] +
a[i][k] * b[k][j];
}
}
}
}

42
Умножение матриц v1.0
#pragma omp parallel
{
#pragma omp for
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
for (k = 0; k < N; k++) {
c[i][j] = c[i][j] +
a[i][k] * b[k][j];
}
}
}
}

Ошибка!
Переменные j, k – общие для всех потоков!

43
Умножение матриц v2.0
#pragma omp parallel
{
#pragma omp for shared(a, b, c) private(j, k)
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
for (k = 0; k < N; k++) {
c[i][j] = c[i][j] +
a[i][k] * b[k][j];
}
}
}
}

44
Директива task (OpenMP 3.0)
int fib(int n)
{
if (n < 2)
return n;
return fib(n - 1) + fib(n - 2);
}


Директива task создает задачу (легковесный поток)



Задачи из пула динамически выполняются группой потоков



Динамическое распределение задача по потокам осуществляется
алгоритмами планирования типа work stealing



Задач может быть намного больше количества потоков
45
Директива task (OpenMP 3.0)
int fib(int n)
{
int x, y;
if (n < 2)
return n;
#pragma omp task shared(x, n)
x = fib(n - 1);
#pragma omp task shared(y, n)
y = fib(n - 2);
#pragma omp taskwait
return x + y;
}
#pragma omp parallel
#pragma omp single
val = fib(n);

Каждый
рекурсивный
вызов – это задача

Ожидаем
завершение
дочерних задач

46
Пример Primes (sequential code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
nprimes++;
}



Программа подсчитывает количество простых чисел
в интервале [start, end]

47
Пример Primes (serial code)
int is_prime_number(int num)
{
int limit, factor = 3;
limit = (int)(sqrtf((double)num) + 0.5f);
while ((factor <= limit) && (num % factor))
factor++;
return (factor > limit);

}

48
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
nprimes++;
}
49
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
nprimes++;
Data
}

race
50
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
#pragma omp critical
nprimes++;
}
51
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
Увеличение счетчика можно
#pragma omp critical
реализовать без блокировки
nprimes++;
(Lock-free algorithm)
}
52
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for reduction(+:nprimes)
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
nprimes++;
}
53
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for reduction(+:nprimes)
for (i = start; i <= end; i += 2) {
Время выполнения
if (is_prime_number(i))
is_prime_number(i)
nprimes++;
зависит от значения i
}
54
Пример Primes (parallel code)
#pragma omp parallel for reduction(+:nprimes)
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
nprimes++;
}
Поток 0
Поток 1
Поток 2

Время выполнения
потоков различно!

Load Imbalance

Поток 3
Поток 4
55
Пример Primes (parallel code)
start = atoi(argv[1]);
end = atoi(argv[2]);
if ((start % 2) == 0 )
start = start + 1;

nprimes = 0;
if (start <= 2)
nprimes++;
#pragma omp parallel for schedule(static, 1)
reduction(+:nprimes)
for (i = start; i <= end; i += 2) {
if (is_prime_number(i))
nprimes++;
}
56
Блокировки (locks)
 Блокировка, мьютекс (lock, mutex) – это объект синхронизации,
который позволяет ограничить одновременный доступ потоков
к разделяемым ресурсам (реализует взаимное исключение)






OpenMP: omp_lock_set/omp_lock_unset
POSIX Pthreads: pthread_mutex_lock/pthread_mutex_unlock
C++11: std::mutex::lock/std::mutex::unlock
C11: mtx_lock/mtx_unlock

 Блокировка (lock) может быть рекурсивной (вложенной) –
один поток может захватывать блокировку несколько раз

57
Spin locks (циклические блокировки)
 Spin lock (блокировка в цикле) – это вид блокировки, при который
процесс ожидающий освобождения блокировки не “засыпает”,
а выполняет цикл ожидания (busy waiting)

 Рекомендуется использовать если время пребывания в критической
секции меньше времени переключения контекстов
 Плюсы: spin lock позволяет быстро среагировать на освобождение
блокировки

 Минусы: spin lock всегда занимает ресурсы процессорного ядра
pthread_spinlock_t lock;
pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
pthread_spin_lock(&lock);
counter++;
pthread_spin_unlock(&lock);
pthread_spin_destroy(&lock);

58
Блокировки чтения-записи (rwlocks)
 Read-write lock – это вид блокировки, которая позволяет
разграничить доступ потоков на запись и чтение разделяемых
структур данных
 Блокировка на запись не может быть получена, пока не освобождены
все блокировки на чтение (rdlock)
int readData(int i, int j)
{
pthread_rwlock_rdlock(&lock);
int result = data[i] + data[j];
pthread_rwlock_unlock(&lock);
return result;
}
void writeData(int i, int j, int value)
{
pthread_rwlock_wrlock(&lock);
data[i] += value;
data[j] -= value;
pthread_rwlock_unlock(&lock);
}

59
Блокировки (locks)
#include <omp.h>

int main()
{
std::vector<int> vec(1000);
std::fill(vec.begin(), vec.end(), 1);
int counter = 0;
omp_lock_t lock;
omp_init_lock(&lock);
#pragma omp parallel for
for (std::vector<int>::size_type i = 0; i < vec.size(); i++) {
if (vec[i] > 0) {
omp_set_lock(&lock);
counter++;
omp_unset_lock(&lock);
}
}
omp_destroy_lock(&lock);
std::cout << "Counter = " << counter << std::endl;
return 0;
}

60
Взаимная блокировка (Deadlock)
 Взаимная блокировка (deadlock, тупик) –
ситуация когда два и более потока находятся в состоянии
бесконечного ожидания ресурсов, захваченных этими
потоками
 Самоблокировка (self deadlock) – ситуация когда поток
пытается повторно захватить блокировку, которую уже
захватил (deadlock возникает если блокировка не является
рекурсивной)

61
Взаимная блокировка (Deadlock)
void deadlock_example()
{
#pragma omp sections
{
#pragma omp section
{
omp_lock_t lock1, lock2;
omp_set_lock(&lock1);
omp_set_lock(&lock2);
// Code
omp_unset_lock(&lock2);
omp_unset_lock(&lock1);
}
#pragma omp section
{
omp_lock_t lock1, lock2;
omp_set_lock(&lock2);
omp_set_lock(&lock1);
// Code
omp_unset_lock(&lock1);
omp_unset_lock(&lock2);
}
}
}

1. T0
захватывает
Lock1

1. T1
захватывает
Lock2

2. T0 ожидает
Lock2

2. T1 ожидает
Lock1

62
OpenMP 4.0: Поддержка ускорителей (GPU)
sum = 0;
#pragma omp target device(acc0) in(B,C)
#pragma omp parallel for reduction(+:sum)
for (i = 0; i < N; i++)
sum += B[i] * C[i]
 omp_set_default_device()
 omp_get_default_device()
 omp_get_num_devices()

63
OpenMP 4.0: SIMD-конструкции
 SIMD-конструкции для векторизации циклов
(SSE, AVX2, AVX-512, AltiVec, …)
void minex(float *a, float *b, float *c, float *d)
{
#pragma omp parallel for simd
for (i = 0; i < N; i++)
d[i] = min(distsq(a[i], b[i]), c[i]);
}

64
OpenMP 4.0: Thread Affinity
 Thread affinity – привязка потоков к процессорным ядрам


#pragma omp parallel proc_bind(master | close | spread)



omp_proc_bind_t omp_get_proc_bind(void)



Env. variable OMP_PLACES

 export OMP_NUM_THREADS=16
 export OMP_PLACES=0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15
 export OMP_PROC_BIND=spread,close

65
OpenMP 4.0: user defined reductions
#pragma omp declare reduction (reduction-identifier :
typename-list : combiner) [identity(identity-expr)]
#pragma omp declare reduction (merge : std::vector<int> :
omp_out.insert(omp_out.end(),
omp_in.begin(), omp_in.end()
))
void schedule(std::vector<int> &v, std::vector<int> &filtered)
{
#pragma omp parallel for reduction (merge : filtered)
for (std:vector<int>::iterator it = v.begin();
it < v.end(); it++)
{
if (filter(*it))
filtered.push_back(*it);
}
}
66
POSIX Threads
 POSIX Threads – это стандарт (POSIX.1c Threads extensions
(IEEE Std 1003.1c-1995)), в котором определяется API
для создания и управления потоками
 Библиотека pthread (pthread.h) ~ 100 функций





Thread management - creating, joining threads etc.
Mutexes
Condition variables
Synchronization between threads using read/write locks and
barriers

 Семфафоры POSIX (префикс sem_) могут работать
с потоками pthread, но не являются частью стандарта
(определены в стандарте POSIX.1b, Real-time extensions
(IEEE Std 1003.1b-1993))
67
POSIX pthreads API
 Всем типы данных и функции начинаются с префикса pthread_
Prefix

Functional group

pthread_

Threads themselves and miscellaneous
subroutines

pthread_attr_

Thread attributes objects

pthread_mutex_

Mutexes

pthread_mutexattr_

Mutex attributes objects.

pthread_cond_

Condition variables

pthread_condattr_

Condition attributes objects

pthread_key_

Thread-specific data keys

pthread_rwlock_

Read/write locks

pthread_barrier_

Synchronization barriers

https://computing.llnl.gov/tutorials/pthreads
68
POSIX pthreads API
 Компиляция программы с поддержкой POSIX pthreads API
Compiler / Platform

Compiler Command

Description

Intel
GNU/Linux

icc -pthread

C

icpc -pthread

C++

PGI
GNU/Linux

pgcc -lpthread

C

pgCC -lpthread

C++

GNU GCC
GNU/Linux, Blue Gene

gcc -pthread

GNU C

g++ -pthread

GNU C++

IBM
Blue Gene

bgxlc_r

/

bgcc_r

bgxlC_r, bgxlc++_r

C (ANSI / non-ANSI)
C++

69
Создание потоков
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg);

 Создает поток с заданными атрибутами attr и запускает в нем
функцию start_routine, передавая ей аргумент arg
 Количество создаваемых в процессе потоков стандартом
не ограничивается и зависит от реализации
 Размер стека потока можно задать через атрибут потока attr
 Размер стека по умолчанию: getrlimit(RLIMIT_STRACK, &rlim);
$ ulimit –s

# The maximum stack size

8192
$ ulimit –u

# The maximum number of processes

1024

# available to a single usere

70
Завершение потоков
 Возврат (return) из стартовой функции (start_routine)
 Вызов pthread_exit()

 Вызов pthread_cancel() другим потоком
 Процесс (и его потоки) завершаются вызовом exit()

71
Создание и завершение потоков
#include <pthread.h>
#define NTHREADS 5
void *thread_fun(void *threadid) {
long tid = (long)threadid;
printf("Hello from %ld!n", tid);
pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
pthread_t threads[NTHREADS];
int rc; long t;
for (t = 0; t < NTHREADS; t++) {
rc = pthread_create(&threads[t], NULL, thread_fun, (void *)t);
if (rc) {
printf("ERROR %dn", rc);
exit(-1);
}
}
pthread_exit(NULL);
}

72
Создание и завершение потоков
#include <pthread.h> prog ./prog.c
$ gcc –pthread –o
#define NTHREADS 5
$ ./prog
void *thread_fun(void *threadid) {
Hello from 1!
long tid = (long)threadid;
Hello from 4! from %ld!n", tid);
printf("Hello
pthread_exit(NULL);
Hello from 0!
}
Hello from 2!
int main(int argc, char *argv[]) {
Hello from 3!
pthread_t threads[NTHREADS];
int rc; long t;
for (t = 0; t < NTHREADS; t++) {
rc = pthread_create(&threads[t], NULL, thread_fun, (void *)t);
if (rc) {
printf("ERROR %dn", rc);
exit(-1);
}
}
pthread_exit(NULL);
}

73
Ожидание потоков
 Функция pthread_join() – позволяет дождаться завершения заданного
потока
 Поток может быть типа “detached” или “joinable” (default)
 К detached-потоку не применима функция pthread_join
(поток создается и существует независимо от других)
 Joinable-поток требует хранения дополнительных данных
 Тип потока можно задать через его атрибуты или вызвав функцию
pthread_detach

74
Ожидание потоков
#include <pthread.h>
#define NTHREADS 5
// ...
int main(int argc, char *argv[]) {
pthread_t threads[NTHREADS];
int rc; long t;
void *status;
for (t = 0; t < NTHREADS; t++) {
rc = pthread_create(&threads[t], NULL, thread_fun,
(void *)t);
}
for (t = 0; t < NTHREADS; t++) {
rc = pthread_join(threads[t], &status);
}
pthread_exit(NULL);
}

75
Синхронизация потоков
 Функция pthread_self() – возвращает идентификатор потока
 Функция pthread_equal() – позволяет сравнить идентификаторы двух
потоков

76
Взаимные исключения (mutex)
 Mutex (mutual exclusion) – это объект синхронизации “взаимное
исключение”
 Мьютексы используются для создания критических секций
(critical sections) – областей кода, которые выполняются в любой
момент времени только одним потоком
 В критических секциях, как правило, содержится код работы
с разделяемыми переменными
 pthread_mutex_init() – инициализирует мьютекс

 pthread_mutex_destroy() – уничтожает мьютекс
 pthread_mutex_lock() – блокирует выполнение потока,
пока он не захватит (acquire) мьютекс
 pthread_mutex_trylock() – осуществляет попытку захватить мьютекс
 pthread_mutex_unlock() – освобождает (release) мьютекс
77
Взаимные исключения (mutex)
node_t *llist_delete(int value)
{
node_t *prev, *current;
prev = &head;
pthread_mutex_lock(&prev->lock);
while ((current = prev->link) != NULL) {
pthread_mutex_lock(&current->lock);
if (current->value == value) {
prev->link = current->link;
pthread_mutex_unlock(&current->lock);
pthread_mutex_unlock(&prev->lock);
current->link = NULL;
return current;
}
pthread_mutex_unlock(&prev->lock);
prev = current;
}
pthread_mutex_unlock(&prev->lock);
return NULL;
}

78
Вычисление числа π
 Приближенное вычисление числа π
1

𝜋=
0

4
2 𝑑𝑥
1+ 𝑥

𝑛

𝜋≈ℎ
𝑖=1

4
1 + (ℎ(𝑖 − 0.5))2

1
ℎ=
𝑛

4,50

4,00
3,50
3,00
2,50
2,00
1,50
1,00

0,50
0,00
0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90

79
pi.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
volatile long double pi = 0.0;
pthread_mutex_t piLock;
long double intervals;
int numThreads;
void *computePI(void *id)
{
long double x, width, localSum = 0;
int i, threadID = *((int*)id);
width = 1.0 / intervals;
for (i = threadID ; i < intervals; i += numThreads) {
x = (i + 0.5) * width;
localSum += 4.0 / (1.0 + x * x);
}
localSum *= width;
pthread_mutex_lock(&piLock);
pi += localSum;
pthread_mutex_unlock(&piLock);
return NULL;
}

80
pi.c (продолжение)
int main(int argc, char **argv)
{
pthread_t *threads;
void *retval;
int *threadID;
int i;
if (argc == 3) {
intervals = atoi(argv[1]);
numThreads = atoi(argv[2]);
threads = malloc(numThreads * sizeof(pthread_t));
threadID = malloc(numThreads * sizeof(int));
pthread_mutex_init(&piLock, NULL);
for (i = 0; i < numThreads; i++) {
threadID[i] = i;
pthread_create(&threads[i], NULL, computePI, threadID + i);
}
for (i = 0; i < numThreads; i++)
pthread_join(threads[i], &retval);

printf("Estimation of pi is %32.30Lf n", pi);
} else {
printf("Usage: ./a.out <numIntervals> <numThreads>n");
}
return 0;
}

81
Windows API для многопоточной обработки


Win32 API Threads CreateThread – системный вызов

HANDLE WINAPI CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);



C run-time library _beginthread (обертка вокруг CreateThread, корректно
инициализирует libc)

uintptr_t _beginthread(void *start_address(void *),
unsigned int stack_size,
void *arglist);



MFC AfxBeginThread – MFC-обертка вокруг CreateThread

CWinThread *AfxBeginThread(...);

82
Windows API для многопоточной обработки
 .NET System.Threading
public sealed class Thread : CriticalFinalizerObject, _Thread

83
C11 threads
#include <threads.h>

void threadfun()
{
printf("Hello from threadn");
}
int main()
{
thrd_t tid;
int rc;
rc = thrd_create(&tid, threadfun, NULL)
if (rc != thrd_success) {
fprintf(stderr, "Error creating threadn");
exit(1);
}
thrd_join(tid, NULL);
return 0;

}

84
Ссылки


Эхтер Ш., Робертс Дж. Многоядерное программирование. – СПб.: Питер,
2010. – 316 с.



Эндрюс Г.Р. Основы многопоточного, параллельного и распределенного
программирования. – М.: Вильямс, 2003. – 512 с.



Darryl Gove. Multicore Application Programming: for Windows, Linux, and
Oracle Solaris. – Addison-Wesley, 2010. – 480 p.



Maurice Herlihy, Nir Shavit. The Art of Multiprocessor Programming. –
Morgan Kaufmann, 2008. – 528 p.



Richard H. Carver, Kuo-Chung Tai. Modern Multithreading : Implementing,
Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32
Programs. – Wiley-Interscience, 2005. – 480 p.



Anthony Williams. C++ Concurrency in Action: Practical Multithreading. –
Manning Publications, 2012. – 528 p.



Träff J.L. Introduction to Parallel Computing //
http://www.par.tuwien.ac.at/teach/WS12/ParComp.html

85

Weitere ähnliche Inhalte

Was ist angesagt?

Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Alexey Paznikov
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Alexey Paznikov
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Mikhail Kurnosov
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияAlexey Paznikov
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...Alexey Paznikov
 
Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...
Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...
Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...Alexey Paznikov
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Mikhail Kurnosov
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
 
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Mikhail Kurnosov
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыAlexey Paznikov
 
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...Alexey Paznikov
 
Лекция 4. Производные типы данных в стандарте MPI
Лекция 4. Производные типы данных в стандарте MPIЛекция 4. Производные типы данных в стандарте MPI
Лекция 4. Производные типы данных в стандарте MPIAlexey Paznikov
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
 

Was ist angesagt? (20)

Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
 
Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...
Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...
Лекция 6. Параллельная сортировка. Алгоритмы комбинаторного поиска. Параллель...
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
 
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
 
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
 
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
Лекция 3. Виртуальные топологии в MPI. Параллельные алгоритмы в стандарте MPI...
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
 
Лекция 4. Производные типы данных в стандарте MPI
Лекция 4. Производные типы данных в стандарте MPIЛекция 4. Производные типы данных в стандарте MPI
Лекция 4. Производные типы данных в стандарте MPI
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизация
 

Ähnlich wie Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)

Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времениTatyanazaxarova
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Mikhail Kurnosov
 
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPВебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPFlyElephant
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...Ontico
 
Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Alex Tutubalin
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Yandex
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
32 подводных камня OpenMP при программировании на Си++
32 подводных камня OpenMP при программировании на Си++32 подводных камня OpenMP при программировании на Си++
32 подводных камня OpenMP при программировании на Си++Tatyanazaxarova
 
Теории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2DТеории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2D0xffAA
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelMikhail Kurnosov
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кодаTatyanazaxarova
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаAndrey Karpov
 

Ähnlich wie Лекция 7: Фибоначчиевы кучи (Fibonacci heaps) (20)

Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времени
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMPВебинар: Основы распараллеливания С++ программ при помощи OpenMP
Вебинар: Основы распараллеливания С++ программ при помощи OpenMP
 
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...Netmap (by luigi rizzo)   простой и удобный opensource фреймворк для обработк...
Netmap (by luigi rizzo) простой и удобный opensource фреймворк для обработк...
 
Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12Доклад в Mail.ru 01.11.12
Доклад в Mail.ru 01.11.12
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
32 подводных камня OpenMP при программировании на Си++
32 подводных камня OpenMP при программировании на Си++32 подводных камня OpenMP при программировании на Си++
32 подводных камня OpenMP при программировании на Си++
 
Теории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2DТеории и практики фунционального программирования - GDG D2D
Теории и практики фунционального программирования - GDG D2D
 
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray ChapelЛекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
Лекция 12 (часть 1): Языки программирования семейства PGAS: Cray Chapel
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 

Mehr von Mikhail Kurnosov

Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Mikhail Kurnosov
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Mikhail Kurnosov
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Mikhail Kurnosov
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Mikhail Kurnosov
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Mikhail Kurnosov
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Mikhail Kurnosov
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)Mikhail Kurnosov
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Mikhail Kurnosov
 
Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Mikhail Kurnosov
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Mikhail Kurnosov
 
Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)Mikhail Kurnosov
 
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Mikhail Kurnosov
 
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Mikhail Kurnosov
 
Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Mikhail Kurnosov
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Mikhail Kurnosov
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовMikhail Kurnosov
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Mikhail Kurnosov
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиMikhail Kurnosov
 
Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Mikhail Kurnosov
 

Mehr von Mikhail Kurnosov (20)

Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
Лекция 5. Основы параллельного программирования (Speedup, Amdahl's law, Paral...
 
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
Лекция 6. Фибоначчиевы кучи (Fibonacci heaps)
 
Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)Лекция 5. B-деревья (B-trees, k-way merge sort)
Лекция 5. B-деревья (B-trees, k-way merge sort)
 
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
Лекция 4. Векторизация кода (Code vectorization: SSE, AVX)
 
Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)Лекция 4. Префиксные деревья (tries, prefix trees)
Лекция 4. Префиксные деревья (tries, prefix trees)
 
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
Лекция 3. Оптимизация доступа к памяти (Memory access optimization, cache opt...
 
Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)Лекция 3. АВЛ-деревья (AVL trees)
Лекция 3. АВЛ-деревья (AVL trees)
 
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
Лекция 2. Оптимизация ветвлений и циклов (Branch prediction and loop optimiz...
 
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
Лекция 2. Красно-чёрные деревья (Red-black trees). Скошенные деревья (Splay t...
 
Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)Лекция 1. Амортизационный анализ (amortized analysis)
Лекция 1. Амортизационный анализ (amortized analysis)
 
Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)Семинар 12. Параллельное программирование на MPI (часть 5)
Семинар 12. Параллельное программирование на MPI (часть 5)
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмов
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимости
 
Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)
 

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)

  • 1. Лекция 7: Многопоточное программирование Часть 3 (Multithreading programming) Курносов Михаил Георгиевич к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет телекоммуникаций и информатики http://www.mkurnosov.net
  • 2. Программный инструментарий Прикладные библиотеки      Intel Threading Building Blocks (TBB) Microsoft Concurrency Runtime Apple Grand Central Dispatch Boost Threads Qthread, MassiveThreads Языки программирования  OpenMP (C/C++/Fortran)  Intel Cilk Plus  С++11 Threads  C11 Threads     C# Threads Java Threads Erlang Threads Haskell Threads Системные библиотеки (System libraries) Уровень пользователя (User space) GNU/Linux Pthreads Thread Thread Уровень ядра (Kernel space) Win32 API/.NET Threads Thread Thread Thread Apple OS X Cocoa, Pthreads Thread Thread … Thread Kernel thread … Kernel thread Системные вызовы (System calls) Kernel thread Kernel thread Kernel thread Kernel thread Kernel thread Kernel thread Process/thread scheduler Операционная система (Operating System) GNU/Linux, Microsoft Windows, Apple OS X, IBM AIX, Oracle Solaris, … Hardware (Multi-core processors, SMP/NUMA) 2
  • 3. Стандарт OpenMP  OpenMP (Open Multi-Processing) – стандарт, определяющий набор директив компилятора, библиотечных процедур и переменных среды окружения для создания многопоточных программ  Текущая версия стандарта – OpenMP 4.0  Требуется поддержка со стороны компилятора www.openmp.org 3
  • 4. OpenMP Compiler Information GNU GCC Option: –fopenmp gcc 4.2 – OpenMP 2.5, gcc 4.4 – OpenMP 3.0, gcc 4.7 – OpenMP 3.1 gcc 4.9 – OpenMP 4.0 Clang (LLVM) OpenMP 3.1 Clang + Intel OpenMP RTL http://clang-omp.github.io/ Intel C/C++, Fortran OpenMP 3.1 Option: –Qopenmp, –openmp Oracle Solaris Studio C/C++/Fortran OpenMP 3.1 Option: –xopenmp Microsoft Visual Studio 2012 C++ Option: /openmp OpenMP 2.0 only Other compilers: IBM XL, PathScale, PGI, Absoft Pro, … http://openmp.org/wp/openmp-compilers/ 4
  • 5. Структура OpenMP-программы  Программа представляется в виде последовательных участков кода (serial code) и параллельных регионов (parallel region)  Каждый поток имеет номер: 0, 1, 2, … 0 0 1 2  Главный поток (master) имеет номер 0  Память процесса (heap) является общей для всех потоков Барьерная синхронизация  OpenMP реализует динамическое управление потоками (task parallelism)  OpenMP: data parallelism + task parallelism 0 0 1 5
  • 6. Пример OpenMP-программы #include <omp.h> int main() { #pragma omp parallel { printf("Thread %dn", omp_get_thread_num()); } return 0; } 6
  • 7. Компиляция OpenMP-программы $ gcc –fopenmp –o prog ./prog.c $ ./prog Thread 0 Thread 1 Thread 3 Thread 2 $ export OMP_NUM_THREADS=2 $ ./prog Thread 0 Thread 1 По умолчанию количество потоков = количеству логических процессоров в системе 7
  • 8. Пример OpenMP-программы #include <omp.h> int main() { #pragma omp parallel { #ifdef _OPENMP printf("Thread %dn", omp_get_thread_num()); #endif } return 0; } 8
  • 9. Директивы OpenMP #pragma omp <директива> [раздел [ [,] раздел]...]  Создание потоков  Распределение вычислений между потоками  Управление пространством видимости переменных  Механизмы синхронизации потоков  … 9
  • 10. Создание потоков (parallel) #pragma omp parallel { /* Этот код выполняется всеми потоками */ } #pragma omp parallel if (expr) { /* Код выполняется потоками если expr = true */ } #pragma omp parallel num_threads(n / 2) { /* Создается n / 2 потоков */ } На выходе из параллельного региона осуществляется барьерная синхронизация – все потоки ждут последнего 10
  • 11. Создание потоков (sections) #pragma omp parallel sections { #pragma omp section { /* Код потока 0 */ } #pragma omp section { /* Код потока 1 */ } } При любых условиях выполняется фиксированное количество потоков (по количеству секций) 11
  • 12. Функции runtime-библиотеки  int omp_get_thread_num() – возвращает номер текущего потока  int omp_get_num_threads() – возвращает количество потоков в параллельном регионе  void omp_set_num_threads(int n)  double omp_get_wtime() 12
  • 13. Директива master #pragma omp parallel { /* Этот код выполняется всеми потоками */ #pragma omp master { /* Код выполняется только потоком 0 */ } /* Этот код выполняется всеми потоками */ } 13
  • 14. Директива single #pragma omp parallel { /* Этот код выполняется всеми потоками */ #pragma omp single { /* Код выполняется только одним потоком */ } /* Этот код выполняется всеми потоками */ } 14
  • 15. Директива for (data parallelism) #define N 13 #pragma omp parallel { #pragma omp for for (i = 0; i < N; i++) { printf("Thread %d i = %dn", omp_get_thread_num(), i); } } Итерации цикла распределяются между потоками i: 0 1 2 Thread 0 3 4 5 Thread 1 6 7 8 Thread 2 9 10 11 12 Thread 3 15
  • 16. Директива for $ OMP_NUM_THREADS=4 ./prog Thread 2 i = 7 Thread 2 i = 8 Thread 2 i = 9 Thread 0 i = 0 Thread 0 i = 1 Thread 0 i = 2 Thread 3 i = 10 Thread 3 i = 11 Thread 3 i = 12 Thread 0 i = 3 Thread 1 i = 4 Thread 1 i = 5 Thread 1 i = 6 16
  • 17. Алгоритмы распределения итераций #define N 13 #pragma omp parallel { #pragma omp for schedule(static, 2) for (i = 0; i < N; i++) { printf("Thread %d i = %dn", omp_get_thread_num(), i); } } Итерации цикла распределяются циклически (round-robin) блоками по 2 итерации i: 0 1 T0 2 3 T1 4 5 T2 6 7 T3 8 9 T0 10 11 T1 12 T2 17
  • 18. Алгоритмы распределения итераций $ OMP_NUM_THREADS=4 ./prog Thread 0 i = 0 Thread 0 i = 1 Thread 0 i = 8 Thread 0 i = 9 Thread 1 i = 2 Thread 1 i = 3 Thread 1 i = 10 Thread 1 i = 11 Thread 3 i = 6 Thread 3 i = 7 Thread 2 i = 4 Thread 2 i = 5 Thread 2 i = 12 18
  • 19. Алгоритмы распределения итераций Алгоритм static, m Описание Цикл делится на блоки по m итераций (до выполнения), которые распределяются по потокам Цикл делится на блоки по m итераций. dynamic, m При выполнении блока из m итераций поток выбирает следующий блок из общего пула guided, m runtime Блоки выделяются динамически. При каждом запросе размер блока уменьшается экспоненциально до m Алгоритм задается пользователем через переменную среды OMP_SCHEDULE 19
  • 20. Директива for (ordered) #define N 7 #pragma omp parallel { #pragma omp for ordered for (i = 0; i < N; i++) { #pragma omp ordered printf("Thread %d i = %dn", omp_get_thread_num(), i); } }  Директива ordered организует последовательное выполнение итераций (i = 0, 1, …) – синхронизация  Поток с i = k ожидает пока потоки с i = k – 1, k – 2, … не выполнят свои итерации 20
  • 21. Директива for (ordered) $ OMP_NUM_THREADS=4 ./prog Thread 0 i = 0 Thread 0 i = 1 Thread 1 i = 2 Thread 1 i = 3 Thread 2 i = 4 Thread 2 i = 5 Thread 3 i = 6 21
  • 22. Директива for (nowait) #define N 7 #pragma omp parallel { #pragma omp for nowait for (i = 0; i < N; i++) { printf("Thread %d i = %dn", omp_get_thread_num(), i); } }  По окончанию цикла потоки не выполняют барьерную синхронизацию  Конструкция nowait применима и к директиве sections 22
  • 23. Директива for (collapse) #define N 3 #define M 4 #pragma omp parallel { #pragma omp for collapse(2) for (i = 0; i < N; i++) { for (j = 0; j < M; j++) printf("Thread %d i = %dn", omp_get_thread_num(), i); } }  сollapse(n) объединяет пространство итераций n циклов в одно i: 0 0,0 1 0,1 T0 + 2 0,2 j: 0 0,3 1,0 T1 1 1,1 2 3 1,2 1,3 T2 2,0 2,1 2,2 T3 2,3 23
  • 24. Директива for (collapse) $ OMP_NUM_THREADS=4 ./prog Thread 2 i = 1 Thread 2 i = 1 Thread 2 i = 2 Thread 0 i = 0 Thread 0 i = 0 Thread 0 i = 0 Thread 3 i = 2 Thread 3 i = 2 Thread 3 i = 2 Thread 1 i = 0 Thread 1 i = 1 Thread 1 i = 1 24
  • 25. Ошибки в многопоточных программах #include <iostream> #include <vector> int main() { std::vector<int> vec(1000); std::fill(vec.begin(), vec.end(), 1); int counter = 0; #pragma omp parallel for for (std::vector<int>::size_type i = 0; i < vec.size(); i++) { if (vec[i] > 0) { counter++; } } std::cout << "Counter = " << counter << std::endl; return 0; } 25
  • 26. Ошибки в многопоточных программах $ g++ –fopenmp –o ompprog ./ompprog.cpp $ ./omprog Counter = 381 $ ./omprog Counter = 909 $ ./omprog Counter = 398 На каждом запуске итоговое значение Counter разное! Правильный результат Counter = 1000 26
  • 27. Ошибки в многопоточных программах #include <iostream> #include <vector> int main() { std::vector<int> vec(1000); Потоки осуществляют конкурентный std::fill(vec.begin(), vec.end(), 1); int counter = 0; доступ к переменной counter – одновременно читают её и записывают #pragma omp parallel for for (std::vector<int>::size_type i = 0; i < vec.size(); i++) { if (vec[i] > 0) { counter++; } } std::cout << "Counter = " << counter << std::endl; return 0; } 27
  • 28. Состояние гонки (Race condition, data race) #pragma omp parallel { counter++; } movl [counter], %eax incl %eax movl %eax, [counter] C++ Идеальная последовательность выполнения инструкций 2-х потоков Thread 0 Memory (counter) Thread 1 0 movl [counter], %eax ← 0 0 incl %eax → movl %eax, [counter] movl [counter], %eax 1 ← 1 1 incl %eax movl %eax, [counter] counter = 2 → 2 28
  • 29. Состояние гонки (Race condition, data race) #pragma omp parallel { counter++; } movl [counter], %eax incl %eax movl %eax, [counter] C++ Возможная последовательность выполнения инструкций 2-х потоков Thread 0 Memory (counter) Thread 1 0 ← movl [counter], %eax 0 incl %eax movl [counter], %eax ← 0 movl %eax, [counter] incl %eax → 1 movl %eax, [counter] → 1 1 Error: Data race counter = 1 29
  • 30. Состояние гонки (Race condition, data race)  Состояние гонки (Race condition, data race) – это состояние программы, в которой несколько потоков одновременно конкурируют за доступ к общей структуре данных (для чтения/записи)  Порядок выполнения потоков заранее не известен – носит случайный характер  Планировщик динамически распределяет процессорное время учитывая текущую загруженность процессорных ядер, а нагрузку (потоки, процессы) создают пользователи, поведение которых носит случайных характер  Состояние гонки данных (Race condition, data race) трудно обнаруживается в программах и воспроизводится в тестах  Состояние гонки данных (Race condition, data race) – это типичный пример Гейзенбага (Heisenbug) 30
  • 31. Обнаружение состояния гонки (Data race) Динамические анализаторы  Valgrind Helgrind, DRD  Intel Thread Checker  Oracle Studio Thread Analyzer  Java ThreadSanitizer  Java Chord Статические анализаторы кода  PVS-Studio (viva64)  … 31
  • 32. Valgrind Helgrind $ g++ -fopenmp -o ompprog ./ompprog.cpp $ valgrind --helgrind ./ompprog ==8238== ==8238== ==8238== ==8238== ... ==8266== Helgrind, a thread error detector Copyright (C) 2007-2012, and GNU GPL'd, by OpenWorks LLP et al. Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info Command: ./ompprog report ---------------------------------------------------------------- ==8266== Possible data race during write of size 4 at 0x7FEFFD358 by thread #3 ==8266== Locks held: none ==8266== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14) ==8266== by 0x3F84A08389: ??? (in /usr/lib64/libgomp.so.1.0.0) ==8266== by 0x4A0A245: ??? (in /usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so) ==8266== by 0x34CFA07C52: start_thread (in /usr/lib64/libpthread-2.17.so) ==8266== by 0x34CF2F5E1C: clone (in /usr/lib64/libc-2.17.so) ==8266== ==8266== This conflicts with a previous write of size 4 by thread #1 ==8266== Locks held: none ==8266== ==8266== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14) by 0x400CE8: main (ompprog.cpp:11)... 32
  • 33. Директивы синхронизации  Директивы синхронизации позволяют управлять порядком выполнения заданных участков кода потоками  #pragma omp critical  #pragma omp atomic  #pragma omp ordered  #pragma omp barrier 33
  • 34. Критические секции #pragma omp parallel for private(v) for (i = 0; i < n; i++) { v = fun(a[i]); #pragma omp critical { sum += v; } } 34
  • 35. Критические секции #pragma omp parallel for private(v) for (i = 0; i < n; i++) { v = fun(a[i]); #pragma omp critical { sum += v; } }  Критическая секция (Critical section) – участок кода в многопоточной программе, выполняемый всеми потоками последовательно  Критические секции снижают степень параллелизма 35
  • 36. Управление видимостью переменных  private(list) – во всех потоках создаются локальные копии переменных (начальное значение)  firstprivate(list) – во всех потоках создаются локальные копии переменных, которые инициализируются их значениями до входа в параллельный регион  lastprivate(list) – во всех потоках создаются локальные копии переменных. По окончанию работы всех потоков локальная переменная вне параллельного региона обновляется значением этой переменной одного из потоков  shared(list) – переменные являются общими для всех потоков 36
  • 37. Атомарные операции #pragma omp parallel for private(v) for (i = 0; i < n; i++) { v = fun(a[i]); #pragma omp atomic sum += v; } 37
  • 38. Атомарные операции #pragma omp parallel for private(v) for (i = 0; i < n; i++) { v = fun(a[i]); #pragma omp atomic sum += v; }  Атомарные операции “легче” критических секций (не используют блокировки)  Lock-free algorithms & data structures 38
  • 39. Параллельная редукция #pragma omp parallel for reduction(+:sum) for (i = 0; i < n; i++) { sum = sum + fun(a[i]); }  Операции директивы reduction: +, *, -, &, |, ^, &&, ||, max, min  OpenMP 4.0 поддерживает пользовательские функции редукции 39
  • 40. Директивы синхронизации #pragma omp { /* Code #pragma /* Code } parallel */ omp barrier */  Директива barrier осуществляет ожидание достижения данной точки программы всеми потоками 40
  • 41. #pragma omp flush #pragma omp { /* Code #pragma /* Code } parallel */ omp flush(a, b) */  Принудительно обновляет в памяти значения переменных (Memory barrier)  Например, в одном потоке выставляем флаг (сигнал к действию) для другого 41
  • 42. Умножение матриц v1.0 #pragma omp parallel { #pragma omp for for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { for (k = 0; k < N; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } } 42
  • 43. Умножение матриц v1.0 #pragma omp parallel { #pragma omp for for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { for (k = 0; k < N; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } } Ошибка! Переменные j, k – общие для всех потоков! 43
  • 44. Умножение матриц v2.0 #pragma omp parallel { #pragma omp for shared(a, b, c) private(j, k) for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { for (k = 0; k < N; k++) { c[i][j] = c[i][j] + a[i][k] * b[k][j]; } } } } 44
  • 45. Директива task (OpenMP 3.0) int fib(int n) { if (n < 2) return n; return fib(n - 1) + fib(n - 2); }  Директива task создает задачу (легковесный поток)  Задачи из пула динамически выполняются группой потоков  Динамическое распределение задача по потокам осуществляется алгоритмами планирования типа work stealing  Задач может быть намного больше количества потоков 45
  • 46. Директива task (OpenMP 3.0) int fib(int n) { int x, y; if (n < 2) return n; #pragma omp task shared(x, n) x = fib(n - 1); #pragma omp task shared(y, n) y = fib(n - 2); #pragma omp taskwait return x + y; } #pragma omp parallel #pragma omp single val = fib(n); Каждый рекурсивный вызов – это задача Ожидаем завершение дочерних задач 46
  • 47. Пример Primes (sequential code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; for (i = start; i <= end; i += 2) { if (is_prime_number(i)) nprimes++; }  Программа подсчитывает количество простых чисел в интервале [start, end] 47
  • 48. Пример Primes (serial code) int is_prime_number(int num) { int limit, factor = 3; limit = (int)(sqrtf((double)num) + 0.5f); while ((factor <= limit) && (num % factor)) factor++; return (factor > limit); } 48
  • 49. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for for (i = start; i <= end; i += 2) { if (is_prime_number(i)) nprimes++; } 49
  • 50. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for for (i = start; i <= end; i += 2) { if (is_prime_number(i)) nprimes++; Data } race 50
  • 51. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for for (i = start; i <= end; i += 2) { if (is_prime_number(i)) #pragma omp critical nprimes++; } 51
  • 52. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for for (i = start; i <= end; i += 2) { if (is_prime_number(i)) Увеличение счетчика можно #pragma omp critical реализовать без блокировки nprimes++; (Lock-free algorithm) } 52
  • 53. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for reduction(+:nprimes) for (i = start; i <= end; i += 2) { if (is_prime_number(i)) nprimes++; } 53
  • 54. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for reduction(+:nprimes) for (i = start; i <= end; i += 2) { Время выполнения if (is_prime_number(i)) is_prime_number(i) nprimes++; зависит от значения i } 54
  • 55. Пример Primes (parallel code) #pragma omp parallel for reduction(+:nprimes) for (i = start; i <= end; i += 2) { if (is_prime_number(i)) nprimes++; } Поток 0 Поток 1 Поток 2 Время выполнения потоков различно! Load Imbalance Поток 3 Поток 4 55
  • 56. Пример Primes (parallel code) start = atoi(argv[1]); end = atoi(argv[2]); if ((start % 2) == 0 ) start = start + 1; nprimes = 0; if (start <= 2) nprimes++; #pragma omp parallel for schedule(static, 1) reduction(+:nprimes) for (i = start; i <= end; i += 2) { if (is_prime_number(i)) nprimes++; } 56
  • 57. Блокировки (locks)  Блокировка, мьютекс (lock, mutex) – это объект синхронизации, который позволяет ограничить одновременный доступ потоков к разделяемым ресурсам (реализует взаимное исключение)     OpenMP: omp_lock_set/omp_lock_unset POSIX Pthreads: pthread_mutex_lock/pthread_mutex_unlock C++11: std::mutex::lock/std::mutex::unlock C11: mtx_lock/mtx_unlock  Блокировка (lock) может быть рекурсивной (вложенной) – один поток может захватывать блокировку несколько раз 57
  • 58. Spin locks (циклические блокировки)  Spin lock (блокировка в цикле) – это вид блокировки, при который процесс ожидающий освобождения блокировки не “засыпает”, а выполняет цикл ожидания (busy waiting)  Рекомендуется использовать если время пребывания в критической секции меньше времени переключения контекстов  Плюсы: spin lock позволяет быстро среагировать на освобождение блокировки  Минусы: spin lock всегда занимает ресурсы процессорного ядра pthread_spinlock_t lock; pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE); pthread_spin_lock(&lock); counter++; pthread_spin_unlock(&lock); pthread_spin_destroy(&lock); 58
  • 59. Блокировки чтения-записи (rwlocks)  Read-write lock – это вид блокировки, которая позволяет разграничить доступ потоков на запись и чтение разделяемых структур данных  Блокировка на запись не может быть получена, пока не освобождены все блокировки на чтение (rdlock) int readData(int i, int j) { pthread_rwlock_rdlock(&lock); int result = data[i] + data[j]; pthread_rwlock_unlock(&lock); return result; } void writeData(int i, int j, int value) { pthread_rwlock_wrlock(&lock); data[i] += value; data[j] -= value; pthread_rwlock_unlock(&lock); } 59
  • 60. Блокировки (locks) #include <omp.h> int main() { std::vector<int> vec(1000); std::fill(vec.begin(), vec.end(), 1); int counter = 0; omp_lock_t lock; omp_init_lock(&lock); #pragma omp parallel for for (std::vector<int>::size_type i = 0; i < vec.size(); i++) { if (vec[i] > 0) { omp_set_lock(&lock); counter++; omp_unset_lock(&lock); } } omp_destroy_lock(&lock); std::cout << "Counter = " << counter << std::endl; return 0; } 60
  • 61. Взаимная блокировка (Deadlock)  Взаимная блокировка (deadlock, тупик) – ситуация когда два и более потока находятся в состоянии бесконечного ожидания ресурсов, захваченных этими потоками  Самоблокировка (self deadlock) – ситуация когда поток пытается повторно захватить блокировку, которую уже захватил (deadlock возникает если блокировка не является рекурсивной) 61
  • 62. Взаимная блокировка (Deadlock) void deadlock_example() { #pragma omp sections { #pragma omp section { omp_lock_t lock1, lock2; omp_set_lock(&lock1); omp_set_lock(&lock2); // Code omp_unset_lock(&lock2); omp_unset_lock(&lock1); } #pragma omp section { omp_lock_t lock1, lock2; omp_set_lock(&lock2); omp_set_lock(&lock1); // Code omp_unset_lock(&lock1); omp_unset_lock(&lock2); } } } 1. T0 захватывает Lock1 1. T1 захватывает Lock2 2. T0 ожидает Lock2 2. T1 ожидает Lock1 62
  • 63. OpenMP 4.0: Поддержка ускорителей (GPU) sum = 0; #pragma omp target device(acc0) in(B,C) #pragma omp parallel for reduction(+:sum) for (i = 0; i < N; i++) sum += B[i] * C[i]  omp_set_default_device()  omp_get_default_device()  omp_get_num_devices() 63
  • 64. OpenMP 4.0: SIMD-конструкции  SIMD-конструкции для векторизации циклов (SSE, AVX2, AVX-512, AltiVec, …) void minex(float *a, float *b, float *c, float *d) { #pragma omp parallel for simd for (i = 0; i < N; i++) d[i] = min(distsq(a[i], b[i]), c[i]); } 64
  • 65. OpenMP 4.0: Thread Affinity  Thread affinity – привязка потоков к процессорным ядрам  #pragma omp parallel proc_bind(master | close | spread)  omp_proc_bind_t omp_get_proc_bind(void)  Env. variable OMP_PLACES  export OMP_NUM_THREADS=16  export OMP_PLACES=0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15  export OMP_PROC_BIND=spread,close 65
  • 66. OpenMP 4.0: user defined reductions #pragma omp declare reduction (reduction-identifier : typename-list : combiner) [identity(identity-expr)] #pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end() )) void schedule(std::vector<int> &v, std::vector<int> &filtered) { #pragma omp parallel for reduction (merge : filtered) for (std:vector<int>::iterator it = v.begin(); it < v.end(); it++) { if (filter(*it)) filtered.push_back(*it); } } 66
  • 67. POSIX Threads  POSIX Threads – это стандарт (POSIX.1c Threads extensions (IEEE Std 1003.1c-1995)), в котором определяется API для создания и управления потоками  Библиотека pthread (pthread.h) ~ 100 функций     Thread management - creating, joining threads etc. Mutexes Condition variables Synchronization between threads using read/write locks and barriers  Семфафоры POSIX (префикс sem_) могут работать с потоками pthread, но не являются частью стандарта (определены в стандарте POSIX.1b, Real-time extensions (IEEE Std 1003.1b-1993)) 67
  • 68. POSIX pthreads API  Всем типы данных и функции начинаются с префикса pthread_ Prefix Functional group pthread_ Threads themselves and miscellaneous subroutines pthread_attr_ Thread attributes objects pthread_mutex_ Mutexes pthread_mutexattr_ Mutex attributes objects. pthread_cond_ Condition variables pthread_condattr_ Condition attributes objects pthread_key_ Thread-specific data keys pthread_rwlock_ Read/write locks pthread_barrier_ Synchronization barriers https://computing.llnl.gov/tutorials/pthreads 68
  • 69. POSIX pthreads API  Компиляция программы с поддержкой POSIX pthreads API Compiler / Platform Compiler Command Description Intel GNU/Linux icc -pthread C icpc -pthread C++ PGI GNU/Linux pgcc -lpthread C pgCC -lpthread C++ GNU GCC GNU/Linux, Blue Gene gcc -pthread GNU C g++ -pthread GNU C++ IBM Blue Gene bgxlc_r / bgcc_r bgxlC_r, bgxlc++_r C (ANSI / non-ANSI) C++ 69
  • 70. Создание потоков int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);  Создает поток с заданными атрибутами attr и запускает в нем функцию start_routine, передавая ей аргумент arg  Количество создаваемых в процессе потоков стандартом не ограничивается и зависит от реализации  Размер стека потока можно задать через атрибут потока attr  Размер стека по умолчанию: getrlimit(RLIMIT_STRACK, &rlim); $ ulimit –s # The maximum stack size 8192 $ ulimit –u # The maximum number of processes 1024 # available to a single usere 70
  • 71. Завершение потоков  Возврат (return) из стартовой функции (start_routine)  Вызов pthread_exit()  Вызов pthread_cancel() другим потоком  Процесс (и его потоки) завершаются вызовом exit() 71
  • 72. Создание и завершение потоков #include <pthread.h> #define NTHREADS 5 void *thread_fun(void *threadid) { long tid = (long)threadid; printf("Hello from %ld!n", tid); pthread_exit(NULL); } int main(int argc, char *argv[]) { pthread_t threads[NTHREADS]; int rc; long t; for (t = 0; t < NTHREADS; t++) { rc = pthread_create(&threads[t], NULL, thread_fun, (void *)t); if (rc) { printf("ERROR %dn", rc); exit(-1); } } pthread_exit(NULL); } 72
  • 73. Создание и завершение потоков #include <pthread.h> prog ./prog.c $ gcc –pthread –o #define NTHREADS 5 $ ./prog void *thread_fun(void *threadid) { Hello from 1! long tid = (long)threadid; Hello from 4! from %ld!n", tid); printf("Hello pthread_exit(NULL); Hello from 0! } Hello from 2! int main(int argc, char *argv[]) { Hello from 3! pthread_t threads[NTHREADS]; int rc; long t; for (t = 0; t < NTHREADS; t++) { rc = pthread_create(&threads[t], NULL, thread_fun, (void *)t); if (rc) { printf("ERROR %dn", rc); exit(-1); } } pthread_exit(NULL); } 73
  • 74. Ожидание потоков  Функция pthread_join() – позволяет дождаться завершения заданного потока  Поток может быть типа “detached” или “joinable” (default)  К detached-потоку не применима функция pthread_join (поток создается и существует независимо от других)  Joinable-поток требует хранения дополнительных данных  Тип потока можно задать через его атрибуты или вызвав функцию pthread_detach 74
  • 75. Ожидание потоков #include <pthread.h> #define NTHREADS 5 // ... int main(int argc, char *argv[]) { pthread_t threads[NTHREADS]; int rc; long t; void *status; for (t = 0; t < NTHREADS; t++) { rc = pthread_create(&threads[t], NULL, thread_fun, (void *)t); } for (t = 0; t < NTHREADS; t++) { rc = pthread_join(threads[t], &status); } pthread_exit(NULL); } 75
  • 76. Синхронизация потоков  Функция pthread_self() – возвращает идентификатор потока  Функция pthread_equal() – позволяет сравнить идентификаторы двух потоков 76
  • 77. Взаимные исключения (mutex)  Mutex (mutual exclusion) – это объект синхронизации “взаимное исключение”  Мьютексы используются для создания критических секций (critical sections) – областей кода, которые выполняются в любой момент времени только одним потоком  В критических секциях, как правило, содержится код работы с разделяемыми переменными  pthread_mutex_init() – инициализирует мьютекс  pthread_mutex_destroy() – уничтожает мьютекс  pthread_mutex_lock() – блокирует выполнение потока, пока он не захватит (acquire) мьютекс  pthread_mutex_trylock() – осуществляет попытку захватить мьютекс  pthread_mutex_unlock() – освобождает (release) мьютекс 77
  • 78. Взаимные исключения (mutex) node_t *llist_delete(int value) { node_t *prev, *current; prev = &head; pthread_mutex_lock(&prev->lock); while ((current = prev->link) != NULL) { pthread_mutex_lock(&current->lock); if (current->value == value) { prev->link = current->link; pthread_mutex_unlock(&current->lock); pthread_mutex_unlock(&prev->lock); current->link = NULL; return current; } pthread_mutex_unlock(&prev->lock); prev = current; } pthread_mutex_unlock(&prev->lock); return NULL; } 78
  • 79. Вычисление числа π  Приближенное вычисление числа π 1 𝜋= 0 4 2 𝑑𝑥 1+ 𝑥 𝑛 𝜋≈ℎ 𝑖=1 4 1 + (ℎ(𝑖 − 0.5))2 1 ℎ= 𝑛 4,50 4,00 3,50 3,00 2,50 2,00 1,50 1,00 0,50 0,00 0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90 79
  • 80. pi.c #include <stdio.h> #include <stdlib.h> #include <pthread.h> volatile long double pi = 0.0; pthread_mutex_t piLock; long double intervals; int numThreads; void *computePI(void *id) { long double x, width, localSum = 0; int i, threadID = *((int*)id); width = 1.0 / intervals; for (i = threadID ; i < intervals; i += numThreads) { x = (i + 0.5) * width; localSum += 4.0 / (1.0 + x * x); } localSum *= width; pthread_mutex_lock(&piLock); pi += localSum; pthread_mutex_unlock(&piLock); return NULL; } 80
  • 81. pi.c (продолжение) int main(int argc, char **argv) { pthread_t *threads; void *retval; int *threadID; int i; if (argc == 3) { intervals = atoi(argv[1]); numThreads = atoi(argv[2]); threads = malloc(numThreads * sizeof(pthread_t)); threadID = malloc(numThreads * sizeof(int)); pthread_mutex_init(&piLock, NULL); for (i = 0; i < numThreads; i++) { threadID[i] = i; pthread_create(&threads[i], NULL, computePI, threadID + i); } for (i = 0; i < numThreads; i++) pthread_join(threads[i], &retval); printf("Estimation of pi is %32.30Lf n", pi); } else { printf("Usage: ./a.out <numIntervals> <numThreads>n"); } return 0; } 81
  • 82. Windows API для многопоточной обработки  Win32 API Threads CreateThread – системный вызов HANDLE WINAPI CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );  C run-time library _beginthread (обертка вокруг CreateThread, корректно инициализирует libc) uintptr_t _beginthread(void *start_address(void *), unsigned int stack_size, void *arglist);  MFC AfxBeginThread – MFC-обертка вокруг CreateThread CWinThread *AfxBeginThread(...); 82
  • 83. Windows API для многопоточной обработки  .NET System.Threading public sealed class Thread : CriticalFinalizerObject, _Thread 83
  • 84. C11 threads #include <threads.h> void threadfun() { printf("Hello from threadn"); } int main() { thrd_t tid; int rc; rc = thrd_create(&tid, threadfun, NULL) if (rc != thrd_success) { fprintf(stderr, "Error creating threadn"); exit(1); } thrd_join(tid, NULL); return 0; } 84
  • 85. Ссылки  Эхтер Ш., Робертс Дж. Многоядерное программирование. – СПб.: Питер, 2010. – 316 с.  Эндрюс Г.Р. Основы многопоточного, параллельного и распределенного программирования. – М.: Вильямс, 2003. – 512 с.  Darryl Gove. Multicore Application Programming: for Windows, Linux, and Oracle Solaris. – Addison-Wesley, 2010. – 480 p.  Maurice Herlihy, Nir Shavit. The Art of Multiprocessor Programming. – Morgan Kaufmann, 2008. – 528 p.  Richard H. Carver, Kuo-Chung Tai. Modern Multithreading : Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs. – Wiley-Interscience, 2005. – 480 p.  Anthony Williams. C++ Concurrency in Action: Practical Multithreading. – Manning Publications, 2012. – 528 p.  Träff J.L. Introduction to Parallel Computing // http://www.par.tuwien.ac.at/teach/WS12/ParComp.html 85