![Page 1: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/1.jpg)
Лекция 7:
Многопоточное программирование
Часть 3
(Multithreading programming)
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
![Page 2: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/2.jpg)
Программный инструментарий
22Hardware (Multi-core processors, SMP/NUMA)
Kernel thread
Process/thread scheduler
Системные вызовы (System calls)
GNU/Linux Pthreads Apple OS X Cocoa, Pthreads
Уровень ядра(Kernel space)
Операционная система (Operating System)GNU/Linux, Microsoft Windows, Apple OS X, IBM AIX, Oracle Solaris, …
Kernel thread
Kernel thread
…
Уровень пользователя
(User space)
Системные библиотеки (System libraries)
Thread Thread Thread Thread…
Win32 API/.NET Threads
Thread Thread Thread Thread
Kernel thread
Kernel thread
Kernel thread
Kernel thread
Kernel thread
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
![Page 3: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/3.jpg)
Стандарт OpenMP
33
OpenMP (Open Multi-Processing) – стандарт, определяющий набор
директив компилятора, библиотечных процедур и переменных среды
окружения для создания многопоточных программ
Текущая версия стандарта – OpenMP 4.0
Требуется поддержка со стороны компилятора
www.openmp.org
![Page 4: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/4.jpg)
OpenMP
44
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 RTLhttp://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/
![Page 5: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/5.jpg)
Структура OpenMP-программы
55
Программа представляется в виде
последовательных участков кода (serial code)
и параллельных регионов (parallel region)
Каждый поток имеет номер: 0, 1, 2, …
Главный поток (master) имеет номер 0
Память процесса (heap) является
общей для всех потоков
OpenMP реализует динамическое управление
потоками (task parallelism)
OpenMP: data parallelism + task parallelism
0
0 1 2
0 1
0Барьерная
синхронизация
![Page 6: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/6.jpg)
Пример OpenMP-программы
66
#include <omp.h>
int main(){
#pragma omp parallel {
printf("Thread %d\n", omp_get_thread_num());}
return 0;}
![Page 7: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/7.jpg)
Компиляция OpenMP-программы
77
$ gcc –fopenmp –o prog ./prog.c$ ./progThread 0Thread 1Thread 3Thread 2
$ export OMP_NUM_THREADS=2$ ./progThread 0Thread 1
По умолчанию количество потоков = количеству
логических процессоров в системе
![Page 8: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/8.jpg)
Пример OpenMP-программы
88
#include <omp.h>
int main(){
#pragma omp parallel {#ifdef _OPENMP
printf("Thread %d\n", omp_get_thread_num());#endif}
return 0;}
![Page 9: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/9.jpg)
Директивы OpenMP
99
#pragma omp <директива> [раздел [ [,] раздел]...]
Создание потоков
Распределение вычислений между потоками
Управление пространством видимости переменных
Механизмы синхронизации потоков
…
![Page 10: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/10.jpg)
Создание потоков (parallel)
1010
#pragma omp parallel{
/* Этот код выполняется всеми потоками */}
#pragma omp parallel if (expr){
/* Код выполняется потоками если expr = true */}
#pragma omp parallel num_threads(n / 2){
/* Создается n / 2 потоков */}
На выходе из параллельного региона осуществляется барьерная
синхронизация – все потоки ждут последнего
![Page 11: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/11.jpg)
Создание потоков (sections)
1111
#pragma omp parallel sections{
#pragma omp section {
/* Код потока 0 */}
#pragma omp section {
/* Код потока 1 */}
}
При любых условиях выполняется фиксированное
количество потоков (по количеству секций)
![Page 12: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/12.jpg)
Функции runtime-библиотеки
1212
int omp_get_thread_num() – возвращает номер текущего
потока
int omp_get_num_threads() – возвращает количество
потоков в параллельном регионе
void omp_set_num_threads(int n)
double omp_get_wtime()
![Page 13: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/13.jpg)
Директива master
1313
#pragma omp parallel{
/* Этот код выполняется всеми потоками */
#pragma omp master{
/* Код выполняется только потоком 0 */}
/* Этот код выполняется всеми потоками */
}
![Page 14: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/14.jpg)
Директива single
1414
#pragma omp parallel{
/* Этот код выполняется всеми потоками */
#pragma omp single{
/* Код выполняется только одним потоком */}
/* Этот код выполняется всеми потоками */
}
![Page 15: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/15.jpg)
Директива for (data parallelism)
1515
#define N 13
#pragma omp parallel{
#pragma omp forfor (i = 0; i < N; i++) {
printf("Thread %d i = %d\n", omp_get_thread_num(), i);
}}
Итерации цикла распределяются между потоками
0 1 2 3 4 5 6 7 8 9 10 11 12i:
Thread 0 Thread 1 Thread 2 Thread 3
![Page 16: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/16.jpg)
Директива for
1616
$ OMP_NUM_THREADS=4 ./progThread 2 i = 7Thread 2 i = 8Thread 2 i = 9Thread 0 i = 0Thread 0 i = 1Thread 0 i = 2Thread 3 i = 10Thread 3 i = 11Thread 3 i = 12Thread 0 i = 3Thread 1 i = 4Thread 1 i = 5Thread 1 i = 6
![Page 17: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/17.jpg)
Алгоритмы распределения итераций
17
#define N 13
#pragma omp parallel{
#pragma omp for schedule(static, 2)for (i = 0; i < N; i++) {
printf("Thread %d i = %d\n", omp_get_thread_num(), i);
}}
0 1 2 3 4 5 6 7 8 9 10 11 12i:
Итерации цикла распределяются циклически (round-robin)
блоками по 2 итерации
T0 T1 T2 T3 T0 T1 T2
![Page 18: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/18.jpg)
Алгоритмы распределения итераций
1818
$ OMP_NUM_THREADS=4 ./progThread 0 i = 0Thread 0 i = 1Thread 0 i = 8Thread 0 i = 9Thread 1 i = 2Thread 1 i = 3Thread 1 i = 10Thread 1 i = 11Thread 3 i = 6Thread 3 i = 7Thread 2 i = 4Thread 2 i = 5Thread 2 i = 12
![Page 19: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/19.jpg)
Алгоритм Описание
static, mЦикл делится на блоки по m итераций (до выполнения), которые распределяются по потокам
dynamic, mЦикл делится на блоки по m итераций.При выполнении блока из m итераций поток выбирает следующий блок из общего пула
guided, mБлоки выделяются динамически. При каждом запросе размер блока уменьшается экспоненциально до m
runtimeАлгоритм задается пользователем через переменную среды OMP_SCHEDULE
Алгоритмы распределения итераций
1919
![Page 20: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/20.jpg)
Директива for (ordered)
2020
#define N 7
#pragma omp parallel {
#pragma omp for orderedfor (i = 0; i < N; i++) {
#pragma omp orderedprintf("Thread %d i = %d\n",
omp_get_thread_num(), i);}
}
Директива ordered организует последовательное
выполнение итераций (i = 0, 1, …) – синхронизация
Поток с i = k ожидает пока потоки с i = k – 1, k – 2, …
не выполнят свои итерации
![Page 21: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/21.jpg)
Директива for (ordered)
2121
$ OMP_NUM_THREADS=4 ./progThread 0 i = 0Thread 0 i = 1Thread 1 i = 2Thread 1 i = 3Thread 2 i = 4Thread 2 i = 5Thread 3 i = 6
![Page 22: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/22.jpg)
Директива for (nowait)
2222
#define N 7
#pragma omp parallel {
#pragma omp for nowaitfor (i = 0; i < N; i++) {
printf("Thread %d i = %d\n", omp_get_thread_num(), i);
}}
По окончанию цикла потоки не выполняют
барьерную синхронизацию
Конструкция nowait применима и к директиве sections
![Page 23: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/23.jpg)
Директива for (collapse)
2323
#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 = %d\n",
omp_get_thread_num(), i);}
}
сollapse(n) объединяет пространство итераций n циклов в одно
0 1 2 0 1 2 3i: j:
0,0 0,1 0,2 0,3 1,0 1,1 1,2 1,3 2,0 2,1 2,2 2,3
T0
+
T1 T2 T3
![Page 24: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/24.jpg)
Директива for (collapse)
2424
$ OMP_NUM_THREADS=4 ./progThread 2 i = 1Thread 2 i = 1Thread 2 i = 2Thread 0 i = 0Thread 0 i = 0Thread 0 i = 0Thread 3 i = 2Thread 3 i = 2Thread 3 i = 2Thread 1 i = 0Thread 1 i = 1Thread 1 i = 1
![Page 25: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/25.jpg)
#include <iostream>#include <vector>
int main(){
std::vector<int> vec(1000);
std::fill(vec.begin(), vec.end(), 1);int counter = 0;
#pragma omp parallel forfor (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
![Page 26: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/26.jpg)
Ошибки в многопоточных программах
2626
$ g++ –fopenmp –o ompprog ./ompprog.cpp
$ ./omprogCounter = 381
$ ./omprogCounter = 909
$ ./omprogCounter = 398
На каждом запуске итоговое значение Counter разное!
Правильный результат Counter = 1000
![Page 27: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/27.jpg)
#include <iostream>#include <vector>
int main(){
std::vector<int> vec(1000);
std::fill(vec.begin(), vec.end(), 1);int counter = 0;
#pragma omp parallel forfor (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
Потоки осуществляют конкурентный доступ к переменной counter –
одновременно читают её и записывают
![Page 28: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/28.jpg)
Thread 0 Thread 1Memory(counter)
0
movl [counter], %eax ← 0
incl %eax 0
movl %eax, [counter] → 1
movl [counter], %eax ← 1
incl %eax 1
movl %eax, [counter] → 2
Состояние гонки (Race condition, data race)
28
#pragma omp parallel{
counter++;}
movl [counter], %eaxincl %eaxmovl %eax, [counter]
C++
Идеальная последовательность выполнения инструкций 2-х потоков
counter = 2
![Page 29: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/29.jpg)
Thread 0 Thread 1Memory(counter)
0
movl [counter], %eax ← 0
incl %eax movl [counter], %eax ← 0
movl %eax, [counter] incl %eax → 1
movl %eax, [counter] → 1
1
Состояние гонки (Race condition, data race)
29
movl [counter], %eaxincl %eaxmovl %eax, [counter]
C++
Возможная последовательность выполнения инструкций 2-х потоков
counter = 1
Error: Data race
#pragma omp parallel{
counter++;}
![Page 30: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/30.jpg)
Состояние гонки (Race condition, data race)
30
Состояние гонки (Race condition, data race) –
это состояние программы, в которой несколько потоков
одновременно конкурируют за доступ к общей структуре
данных (для чтения/записи)
Порядок выполнения потоков заранее не известен –
носит случайный характер
Планировщик динамически распределяет процессорное время
учитывая текущую загруженность процессорных ядер,
а нагрузку (потоки, процессы) создают пользователи, поведение
которых носит случайных характер
Состояние гонки данных (Race condition, data race) трудно
обнаруживается в программах и воспроизводится в тестах
Состояние гонки данных (Race condition, data race) –
это типичный пример Гейзенбага (Heisenbug)
![Page 31: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/31.jpg)
Обнаружение состояния гонки (Data race)
31
Динамические анализаторы
Valgrind Helgrind, DRD
Intel Thread Checker
Oracle Studio Thread Analyzer
Java ThreadSanitizer
Java Chord
Статические анализаторы кода
PVS-Studio (viva64)
…
![Page 32: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/32.jpg)
==8238== Helgrind, a thread error detector
==8238== Copyright (C) 2007-2012, and GNU GPL'd, by OpenWorks LLP et al.
==8238== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==8238== Command: ./ompprog report
...
==8266== ----------------------------------------------------------------
==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== at 0x400E6E: main._omp_fn.0 (ompprog.cpp:14)==8266== by 0x400CE8: main (ompprog.cpp:11)...
Valgrind Helgrind
32
$ g++ -fopenmp -o ompprog ./ompprog.cpp
$ valgrind --helgrind ./ompprog
![Page 33: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/33.jpg)
Директивы синхронизации
3333
Директивы синхронизации позволяют управлять
порядком выполнения заданных участков кода потоками
#pragma omp critical
#pragma omp atomic
#pragma omp ordered
#pragma omp barrier
![Page 34: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/34.jpg)
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp critical
{
sum += v;
}
}
Критические секции
3434
![Page 35: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/35.jpg)
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp critical
{
sum += v;
}
}
Критическая секция (Critical section) – участок кода
в многопоточной программе, выполняемый всеми
потоками последовательно
Критические секции снижают степень параллелизма
Критические секции
3535
![Page 36: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/36.jpg)
Управление видимостью переменных
3636
private(list) – во всех потоках создаются локальные копии
переменных (начальное значение)
firstprivate(list) – во всех потоках создаются локальные
копии переменных, которые инициализируются их
значениями до входа в параллельный регион
lastprivate(list) – во всех потоках создаются локальные
копии переменных. По окончанию работы всех потоков
локальная переменная вне параллельного региона
обновляется значением этой переменной одного из
потоков
shared(list) – переменные являются общими для всех
потоков
![Page 37: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/37.jpg)
Атомарные операции
3737
#pragma omp parallel for private(v)
for (i = 0; i < n; i++) {
v = fun(a[i]);
#pragma omp atomic
sum += v;
}
![Page 38: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/38.jpg)
Атомарные операции
3838
#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
![Page 39: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/39.jpg)
Параллельная редукция
3939
#pragma omp parallel for reduction(+:sum)
for (i = 0; i < n; i++) {
sum = sum + fun(a[i]);
}
Операции директивы reduction:
+, *, -, &, |, ^, &&, ||, max, min
OpenMP 4.0 поддерживает пользовательские
функции редукции
![Page 40: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/40.jpg)
Директивы синхронизации
4040
#pragma omp parallel
{
/* Code */
#pragma omp barrier
/* Code */
}
Директива barrier осуществляет ожидание достижения
данной точки программы всеми потоками
![Page 41: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/41.jpg)
#pragma omp flush
4141
#pragma omp parallel
{
/* Code */
#pragma omp flush(a, b)
/* Code */
}
Принудительно обновляет в памяти значения
переменных (Memory barrier)
Например, в одном потоке выставляем флаг
(сигнал к действию) для другого
![Page 42: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/42.jpg)
Умножение матриц v1.0
4242
#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];
}
}
}
}
![Page 43: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/43.jpg)
Умножение матриц v1.0
4343
#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 – общие для всех потоков!
![Page 44: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/44.jpg)
Умножение матриц v2.0
4444
#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];
}
}
}
}
![Page 45: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/45.jpg)
Директива task (OpenMP 3.0)
4545
int fib(int n)
{
if (n < 2)
return n;
return fib(n - 1) + fib(n - 2);
}
Директива task создает задачу (легковесный поток)
Задачи из пула динамически выполняются группой потоков
Динамическое распределение задача по потокам осуществляется
алгоритмами планирования типа work stealing
Задач может быть намного больше количества потоков
![Page 46: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/46.jpg)
Директива task (OpenMP 3.0)
4646
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 taskwaitreturn x + y;
}
#pragma omp parallel#pragma omp single
val = fib(n);
Каждый
рекурсивный
вызов – это задача
Ожидаем
завершение
дочерних задач
![Page 47: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/47.jpg)
Пример Primes (sequential code)
4747
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]
![Page 48: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/48.jpg)
Пример Primes (serial code)
4848
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);
}
![Page 49: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/49.jpg)
start = atoi(argv[1]);end = atoi(argv[2]);
if ((start % 2) == 0 )start = start + 1;
nprimes = 0;if (start <= 2)
nprimes++;
#pragma omp parallel forfor (i = start; i <= end; i += 2) {
if (is_prime_number(i))nprimes++;
}
Пример Primes (parallel code)
4949
![Page 50: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/50.jpg)
start = atoi(argv[1]);end = atoi(argv[2]);
if ((start % 2) == 0 )start = start + 1;
nprimes = 0;if (start <= 2)
nprimes++;
#pragma omp parallel forfor (i = start; i <= end; i += 2) {
if (is_prime_number(i))nprimes++;
}
Пример Primes (parallel code)
5050
Data race
![Page 51: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/51.jpg)
start = atoi(argv[1]);end = atoi(argv[2]);
if ((start % 2) == 0 )start = start + 1;
nprimes = 0;if (start <= 2)
nprimes++;
#pragma omp parallel forfor (i = start; i <= end; i += 2) {
if (is_prime_number(i))#pragma omp criticalnprimes++;
}
Пример Primes (parallel code)
5151
![Page 52: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/52.jpg)
start = atoi(argv[1]);end = atoi(argv[2]);
if ((start % 2) == 0 )start = start + 1;
nprimes = 0;if (start <= 2)
nprimes++;
#pragma omp parallel forfor (i = start; i <= end; i += 2) {
if (is_prime_number(i))#pragma omp criticalnprimes++;
}
Пример Primes (parallel code)
5252
Увеличение счетчика можно реализовать без блокировки
(Lock-free algorithm)
![Page 53: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/53.jpg)
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++;
}
Пример Primes (parallel code)
5353
![Page 54: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/54.jpg)
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++;
}
Пример Primes (parallel code)
5454
Время выполнения
is_prime_number(i)
зависит от значения i
![Page 55: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/55.jpg)
#pragma omp parallel for reduction(+:nprimes) for (i = start; i <= end; i += 2) {
if (is_prime_number(i))nprimes++;
}
Пример Primes (parallel code)
5555
Поток 0
Поток 1
Поток 2
Поток 3
Поток 4
Время выполнения потоков различно!
Load Imbalance
![Page 56: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/56.jpg)
Пример Primes (parallel code)
5656
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++;}
![Page 57: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/57.jpg)
Блокировки (locks)
5757
Блокировка, мьютекс (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) может быть рекурсивной (вложенной) –
один поток может захватывать блокировку несколько раз
![Page 58: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/58.jpg)
pthread_spinlock_t lock;pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
pthread_spin_lock(&lock);counter++;pthread_spin_unlock(&lock);
pthread_spin_destroy(&lock);
Spin locks (циклические блокировки)
5858
Spin lock (блокировка в цикле) – это вид блокировки, при который
процесс ожидающий освобождения блокировки не “засыпает”,
а выполняет цикл ожидания (busy waiting)
Рекомендуется использовать если время пребывания в критической
секции меньше времени переключения контекстов
Плюсы: spin lock позволяет быстро среагировать на освобождение
блокировки
Минусы: spin lock всегда занимает ресурсы процессорного ядра
![Page 59: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/59.jpg)
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);
}
Блокировки чтения-записи (rwlocks)
5959
Read-write lock – это вид блокировки, которая позволяет
разграничить доступ потоков на запись и чтение разделяемых
структур данных
Блокировка на запись не может быть получена, пока не освобождены
все блокировки на чтение (rdlock)
![Page 60: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/60.jpg)
#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 forfor (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;
}
Блокировки (locks)
6060
![Page 61: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/61.jpg)
Взаимная блокировка (Deadlock)
6161
Взаимная блокировка (deadlock, тупик) –
ситуация когда два и более потока находятся в состоянии
бесконечного ожидания ресурсов, захваченных этими
потоками
Самоблокировка (self deadlock) – ситуация когда поток
пытается повторно захватить блокировку, которую уже
захватил (deadlock возникает если блокировка не является
рекурсивной)
![Page 62: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/62.jpg)
void deadlock_example(){#pragma omp sections {
#pragma omp section{
omp_lock_t lock1, lock2; omp_set_lock(&lock1);omp_set_lock(&lock2);// Codeomp_unset_lock(&lock2);omp_unset_lock(&lock1);
}#pragma omp section{
omp_lock_t lock1, lock2; omp_set_lock(&lock2);omp_set_lock(&lock1);// Codeomp_unset_lock(&lock1);omp_unset_lock(&lock2);
}}}
Взаимная блокировка (Deadlock)
6262
1. T0захватывает Lock1
2. T0 ожидает Lock2
1. T1захватывает Lock2
2. T1 ожидает Lock1
![Page 63: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/63.jpg)
OpenMP 4.0: Поддержка ускорителей (GPU)
6363
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()
![Page 64: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/64.jpg)
OpenMP 4.0: SIMD-конструкции
6464
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]);
}
SIMD-конструкции для векторизации циклов
(SSE, AVX2, AVX-512, AltiVec, …)
![Page 65: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/65.jpg)
OpenMP 4.0: Thread Affinity
6565
#pragma omp parallel proc_bind(master | close | spread)
omp_proc_bind_t omp_get_proc_bind(void)
Env. variable OMP_PLACES
Thread affinity – привязка потоков к процессорным ядрам
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
![Page 66: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/66.jpg)
#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);
}
}
OpenMP 4.0: user defined reductions
6666
#pragma omp declare reduction (reduction-identifier : typename-list : combiner) [identity(identity-expr)]
![Page 67: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/67.jpg)
POSIX Threads
6767
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))
![Page 68: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/68.jpg)
POSIX pthreads API
6868
Всем типы данных и функции начинаются с префикса 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
![Page 69: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/69.jpg)
POSIX pthreads API
6969
Compiler / Platform Compiler Command Description
Intel GNU/Linux
icc -pthread C
icpc -pthread C++
PGIGNU/Linux
pgcc -lpthread C
pgCC -lpthread C++
GNU GCCGNU/Linux, Blue Gene
gcc -pthread GNU C
g++ -pthread GNU C++
IBMBlue Gene
bgxlc_r / bgcc_r C (ANSI / non-ANSI)
bgxlC_r, bgxlc++_r C++
Компиляция программы с поддержкой POSIX pthreads API
![Page 70: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/70.jpg)
Создание потоков
7070
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
![Page 71: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/71.jpg)
Завершение потоков
7171
Возврат (return) из стартовой функции (start_routine)
Вызов pthread_exit()
Вызов pthread_cancel() другим потоком
Процесс (и его потоки) завершаются вызовом exit()
![Page 72: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/72.jpg)
#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 %d\n", rc); exit(-1);
} } pthread_exit(NULL);
}
Создание и завершение потоков
7272
![Page 73: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/73.jpg)
#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 %d\n", rc); exit(-1);
} } pthread_exit(NULL);
}
Создание и завершение потоков
7373
$ gcc –pthread –o prog ./prog.c
$ ./prog
Hello from 1!
Hello from 4!
Hello from 0!
Hello from 2!
Hello from 3!
![Page 74: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/74.jpg)
Ожидание потоков
7474
Функция pthread_join() – позволяет дождаться завершения заданного
потока
Поток может быть типа “detached” или “joinable” (default)
К detached-потоку не применима функция pthread_join
(поток создается и существует независимо от других)
Joinable-поток требует хранения дополнительных данных
Тип потока можно задать через его атрибуты или вызвав функцию
pthread_detach
![Page 75: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/75.jpg)
#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);
}
Ожидание потоков
7575
![Page 76: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/76.jpg)
Синхронизация потоков
7676
Функция pthread_self() – возвращает идентификатор потока
Функция pthread_equal() – позволяет сравнить идентификаторы двух
потоков
![Page 77: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/77.jpg)
Взаимные исключения (mutex)
7777
Mutex (mutual exclusion) – это объект синхронизации “взаимное
исключение”
Мьютексы используются для создания критических секций
(critical sections) – областей кода, которые выполняются в любой
момент времени только одним потоком
В критических секциях, как правило, содержится код работы
с разделяемыми переменными
pthread_mutex_init() – инициализирует мьютекс
pthread_mutex_destroy() – уничтожает мьютекс
pthread_mutex_lock() – блокирует выполнение потока,
пока он не захватит (acquire) мьютекс
pthread_mutex_trylock() – осуществляет попытку захватить мьютекс
pthread_mutex_unlock() – освобождает (release) мьютекс
![Page 78: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/78.jpg)
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(¤t->lock); if (current->value == value) {
prev->link = current->link; pthread_mutex_unlock(¤t->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;
}
Взаимные исключения (mutex)
7878
![Page 79: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/79.jpg)
0,00
0,50
1,00
1,50
2,00
2,50
3,00
3,50
4,00
4,50
0,00 0,10 0,20 0,30 0,40 0,50 0,60 0,70 0,80 0,90
Вычисление числа π
7979
𝜋 =
0
14
1 + 𝑥2𝑑𝑥 𝜋 ≈ ℎ
𝑖=1
𝑛4
1 + (ℎ(𝑖 − 0.5))2ℎ =1
𝑛
Приближенное вычисление числа π
![Page 80: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/80.jpg)
#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;
}
pi.c
8080
![Page 81: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/81.jpg)
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;
}
pi.c (продолжение)
8181
![Page 82: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/82.jpg)
CWinThread *AfxBeginThread(...);
Windows API для многопоточной обработки
8282
Win32 API Threads CreateThread – системный вызов
C run-time library _beginthread (обертка вокруг CreateThread, корректно
инициализирует libc)
HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId
);
uintptr_t _beginthread(void *start_address(void *), unsigned int stack_size, void *arglist);
MFC AfxBeginThread – MFC-обертка вокруг CreateThread
![Page 83: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/83.jpg)
public sealed class Thread : CriticalFinalizerObject, _Thread
Windows API для многопоточной обработки
8383
.NET System.Threading
![Page 84: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/84.jpg)
#include <threads.h>
void threadfun(){
printf("Hello from thread\n");}
int main(){
thrd_t tid;int rc;
rc = thrd_create(&tid, threadfun, NULL)if (rc != thrd_success) {
fprintf(stderr, "Error creating thread\n");exit(1);
} thrd_join(tid, NULL); return 0;
}
C11 threads
8484
![Page 85: Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)](https://reader035.vdocuments.pub/reader035/viewer/2022081720/5495b2b5ac79590e2e8b4f43/html5/thumbnails/85.jpg)
Ссылки
8585
Эхтер Ш., Робертс Дж. Многоядерное программирование. – СПб.: Питер,
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