SlideShare a Scribd company logo
1 of 54
Download to read offline
Лекция 8:
Intel Threading Building Blocks
(Multithreading programming)
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
Intel Threading Building Blocks
 Intel Treading Building Blocks (TBB) –
это кроссплатформенная библиотека шаблонов
C++ для создания многопоточных программ
 История развития:
o
o
o
o
o
o
o
o

2006 – Intel TBB v1.0 (Intel compiler only)
2007 – Intel TBB v2.0 (Open Source, GPLv2)
2008 – Intel TBB v2.1 (thread affinity, cancellation)
2009 – Intel TBB v2.2 (C++0x lambda functions)
…
2011 – Intel TBB v4.0
2012 – Intel TBB v4.1
2013 – Intel TBB v.4.2
http://threadingbuildingblocks.org

2
Intel Threading Building Blocks
 Open Source Community Version GPL v2

 Поддерживаемые операционные системы:
o Microsoft Windows {XP, 7, Server 2008, …}
o GNU/Linux + Android
o Apple Mac OS X 10.7.4, …

http://threadingbuildingblocks.org

3
Состав Intel TBB
 Алгоритмы: parallel_for, parallel_reduce,
parallel_scan, parallel_while, parallel_do,
parallel_pipeline, parallel_sort

 Контейнеры: concurrent_queue,
concurrent_vector, concurrent_hash_map

 Аллокаторы памяти: scalable_malloc, scalable_free,
scalable_realloc, scalable_calloc,
scalable_allocator, cache_aligned_allocator

 Мьютексы: mutex, spin_mutex, queuing_mutex,
spin_rw_mutex, queuing_rw_mutex, recursive mutex

 Атомарные операции: fetch_and_add,
fetch_and_increment, fetch_and_decrement,
compare_and_swap, fetch_and_store

 Таймеры, планировщик задач

4
Состав Intel TBB
 Алгоритмы: parallel_for, parallel_reduce,
parallel_scan, parallel_while, parallel_do,
parallel_pipeline, parallel_sort

 Контейнеры: concurrent_queue,
concurrent_vector, concurrent_hash_map

 Аллокаторы памяти: scalable_malloc, scalable_free,
scalable_realloc, scalable_calloc,
scalable_allocator, cache_aligned_allocator

 Мьютексы: mutex, spin_mutex, queuing_mutex,
spin_rw_mutex, queuing_rw_mutex, recursive mutex

 Атомарные операции: fetch_and_add,
fetch_and_increment, fetch_and_decrement,
compare_and_swap, fetch_and_store

 Task-based parallelism (fork-join) + work stealing

5
Intel Threading Building Blocks
 Intel TBB позволяет абстрагироваться от низкоуровневых
потоков и распараллеливать программу в терминах
параллельно выполняющихся задач (task parallelism)
 Задачи TBB “легче” потоков операционной системы
 Планировщик TBB использует механизм “work stealing”
для распределения задач по потокам
 Все компоненты Intel TBB определены в пространстве
имен C++ (namespace) “tbb”

6
Компиляция программ с Intel TBB
GNU/Linux
$ g++ –Wall –o prog ./prog.cpp –ltbb

Microsoft Windows (Intel C++ Compiler)
C:> icl /MD prog.cpp tbb.lib

7
Intel TBB: Hello World!
//
// tbb_hello.cpp: TBB Hello World
//
#include <cstdio>
#include <tbb/tbb.h>
// Function object
class MyTask {
public:
MyTask(const char *name): name_(name) {}

void operator()() const
{
// Task code
std::printf("Hello from task %sn", name_);
}
private:
const char *name_;
};

8
Intel TBB: Hello World! (продолжение)
int main( )
{
tbb::task_group tg;
tg.run(MyTask("1"));
tg.run(MyTask("2"));
tg.wait();

// Spawn task
// Spawn task
// Wait tasks

return 0;
}

9
Компиляция и запуск tbb_hello
$ g++ -Wall -I~/opt/tbb/include 

-L~/opt/tbb/lib 
-o tbb_hello 
./tbb_hello.cpp -ltbb
$ ./tbb_hello
Hello from task 2

Hello from task 1

10
Инициализация библиотеки
 Любой поток использующий алгоритмы или планировщик TBB
должен иметь инициализированный объект
tbb::task_scheduler_init
 TBB >= 2.2 автоматически инициализирует планировщик
 Явная инициализация планировщика позволяет:
 управлять когда создается и уничтожается планировщик
 устанавливать количество используемых потоков
выполнения
 устанавливать размер стека для потоков выполнения

11
Инициализация библиотеки
 Явная инициализация планировщика
#include <tbb/task_scheduler_init.h>

int main()
{
tbb::task_scheduler_init init;
return 0;

}

12
Инициализация библиотеки
 Конструктор класса task_scheduler_init принимает
два параметра:
task_scheduler_init(int max_threads = automatic,
stack_size_type thread_stack_size = 0);

 Допустимые значения параметра max_threads:

 task_scheduler_init::automatic –
количество потоков определяется автоматически
 task_scheduler_init::deferred –
инициализация откладывается до явного вызова метода
task_scheduler_init::initialize(max_threads)
 Положительное целое – количество потоков
13
Инициализация библиотеки
#include <iostream>
#include <tbb/task_scheduler_init.h>
int main()
{
int n = tbb::task_scheduler_init::default_num_threads();
for (int p = 1; p <= n; ++p) {
// Construct task scheduler with p threads
tbb::task_scheduler_init init(p);
std::cout << "Is active = " << init.is_active()
<< std::endl;
}
return 0;
}

14
Распараллеливание циклов
 В TBB реализованы шаблоны параллельных алгоритмов
 parallel_for
 parallel_reduce
 parallel_scan
 parallel_do

 parallel_for_each
 parallel_pipeline
 parallel_sort
 parallel_invoke
15
parallel_for
void saxpy(float a, float *x, float *y, size_t n)
{
for (size_t i = 0; i < n; ++i)
y[i] += a * x[i];
}

 parallel_for позволяет разбить пространство итерации
на блоки (chunks), которые обрабатываются разными
потоками
 Требуется создать класс, в котором перегруженный
оператор вызова функции operator() содержит код
обработки блока итераций
16
parallel_for
#include
#include
#include
#include
#include

<iostream>
<tbb/task_scheduler_init.h>
<tbb/tick_count.h>
<tbb/parallel_for.h>
<tbb/blocked_range.h>

class saxpy_par {
public:
saxpy_par(float a, float *x, float *y):
a_(a), x_(x), y_(y) {}
void operator()(const blocked_range<size_t> &r) const
{
for (size_t i = r.begin(); i != r.end(); ++i)
y_[i] += a_ * x_[i];
}
private:
float const a_;
float *const x_;
float *const y_;
};

17
parallel_for
int main()
{
float a = 2.0;
float *x, *y;
size_t n = 100000000;
x = new float[n];
y = new float[n];
for (size_t i = 0; i < n; ++i)
x[i] = 5.0;
tick_count t0 = tick_count::now();
task_scheduler_init init(4);
parallel_for(blocked_range<size_t>(0, n), saxpy_par(a, x, y),
auto_partitioner());
tick_count t1 = tick_count::now();
cout << "Time: " << (t1 - t0).seconds() << " sec." << endl;
delete[] x;
delete[] y;
return 0;
}

18
parallel_for
int main()
{ Класс blocked_range(begin, end, grainsize) описывает одномерное

float a = 2.0;
пространство итераций
float *x, *y;
size_t n = 100000000;
 В Intel TBB доступно описание многомерных пространств итераций

(blocked_range2d, ...)
x = new float[n];
y = new float[n];
for (size_t i = 0; i < n; ++i)
x[i] = 5.0;
tick_count t0 = tick_count::now();
task_scheduler_init init(4);
parallel_for(blocked_range<size_t>(0, n), saxpy_par(a, x, y),
auto_partitioner());
tick_count t1 = tick_count::now();
cout << "Time: " << (t1 - t0).seconds() << " sec." << endl;
delete[] x;
delete[] y;
return 0;
}

19
affinity_partitioner
int main()
{
// ...
static affinity_partitioner ap;
parallel_for(blocked_range<size_t>(0, n),
saxpy_par(a, x, y), ap);
// ...
return 0;
}

 Класс affinity_partitioner запоминает какими потоками
выполнялись предыдущие итерации и пытается
распределять блоки итераций с учетом этой информации
– последовательные блоки назначаются на один и тот же
поток для эффективного использования кеш-памяти
20
parallel_for (C++11 lambda expressions)
int main()
{
// ...
x = new float[n];
y = new float[n];
for (size_t i = 0; i < n; ++i)
x[i] = 5.0;
tick_count t0 = tick_count::now();
parallel_for(blocked_range<size_t>(0, n),
[=](const blocked_range<size_t>& r) {
for (size_t i = r.begin(); i != r.end(); ++i)
y[i] += a * x[i];
}
);
tick_count t1 = tick_count::now();
cout << "Time: " << (t1 - t0).seconds() << " sec." << endl;

delete[] x;
delete[] y;
return 0;
}

21
parallel_for (C++11 lambda expressions)
int main()
Анонимная функция (лямбда-функция, С++11)
{
 [=] – захватить все автоматические переменные
// ...
 (const blocked_range …) – аргументы функции
x = new float[n];
 { ... } – код функции
y = new float[n];
for (size_t i = 0; i < n; ++i)
x[i] = 5.0;
tick_count t0 = tick_count::now();
parallel_for(blocked_range<size_t>(0, n),
[=](const blocked_range<size_t>& r) {
for (size_t i = r.begin(); i != r.end(); ++i)
y[i] += a * x[i];
}
);
tick_count t1 = tick_count::now();
cout << "Time: " << (t1 - t0).seconds() << " sec." << endl;

delete[] x;
delete[] y;
return 0;
}

22
parallel_reduce
float reduce(float *x, size_t n)
{
float sum = 0.0;
for (size_t i = 0; i < n; ++i)
sum += x[i];
return sum;
}

 parallel_reduce позволяет распараллеливать циклы
и выполнять операцию редукции

23
parallel_reduce
class reduce_par {
public:
float sum;
void operator()(const blocked_range<size_t> &r)
{
float sum_local = sum;
float *xloc = x_;
size_t end = r.end();
for (size_t i = r.begin(); i != end; ++i)
sum_local += xloc[i];
sum = sum_local;
}
// Splitting constructor: вызывается при порождении новой задачи
reduce_par(reduce_par& r, split): sum(0.0), x_(r.x_) {}
// Join: объединяет результаты двух задач (текущей и r)
void join(const reduce_par& r) {sum += r.sum;}
reduce_par(float *x): sum(0.0), x_(x) {}
private:
float *x_;
};

24
parallel_reduce
int main()
{
size_t n = 10000000;
float *x = new float[n];
for (size_t i = 0; i < n; ++i)
x[i] = 1.0;
tick_count t0 = tick_count::now();
reduce_par r(x);
parallel_reduce(blocked_range<size_t>(0, n), r);
tick_count t1 = tick_count::now();
cout << "Reduce: " << std::fixed << r.sum << "n";
cout << "Time: " << (t1 - t0).seconds() << " sec." << endl;
delete[] x;
return 0;
}

25
parallel_sort
void parallel_sort(RandomAccessIterator begin,
RandomAccessIterator end,
const Compare& comp);

 parallel_sort позволяет упорядочивать последовательности
элементов
 Применяется детерминированный алгоритм
нестабильной сортировки с трудоемкостью O(nlogn) –
алгоритм не гарантирует сохранения порядка следования
элементов с одинаковыми ключами

26
parallel_sort
#include <cstdlib>
#include <tbb/parallel_sort.h>
using namespace std;
using namespace tbb;
int main()
{
size_t n = 10;
float *x = new float[n];
for (size_t i = 0; i < n; ++i)
x[i] = static_cast<float>(rand()) / RAND_MAX * 100;
parallel_sort(x, x + n, std::greater<float>());
delete[] x;
return 0;

}

27
Планировщик задач (Task scheduler)
 Intel TBB позволяет абстрагироваться от реальных
потоков операционной системы и разрабатывать
программу в терминах параллельных задач
(task-based parallel programming)
 Запуск TBB-задачи примерно в 18 раз быстрее запуска
потока POSIX в GNU/Linux (в Microsoft Windows
примерно в 100 раз быстрее)
 В отличии от планировщика POSIX-потоков в GNU/Linux
планировщик TBB реализует “не справедливую” (unfair)
политику распределения задач по потокам
28
Числа Фибоначчи: sequential version
int fib(int n)
{
if (n < 2)
return n;
return fib(n - 1) + fib(n - 2);
}

29
Числа Фибоначчи: parallel version
int fib_par(int n)
{
int val;
fibtask& t = *new(task::allocate_root()) fibtask(n, &val);
task::spawn_root_and_wait(t);
return val;
}


allocate_root выделяет память под корневую задачу (task) класса fibtask



spawn_root_and_wait запускает задачу на выполнение и ожидает её
завершения

30
Числа Фибоначчи: parallel version
class fibtask: public task {
public:
const int n;
int* const val;
fibtask(int n_, int* val_): n(n_), val(val_) {}

};

task* execute()
{
if (n < 10) {
*val = fib(n);
// Use sequential version
} else {
int x, y;
fibtask& a = *new(allocate_child()) fibtask(n - 1, &x);
fibtask& b = *new(allocate_child()) fibtask(n - 2, &y);
// ref_count: 2 children + 1 for the wait
set_ref_count(3);
spawn(b);
spawn_and_wait_for_all(a);
 spawn запускает задачу на выполнение
*val = x + y;
и не ожидает её завершения
}
 spawn_and_wait_for_all – запускает
return NULL;
задачу и ожидает завершения всех
}
дочерних задач

31
Числа Фибоначчи: parallel version
int main()
{
int n = 42;
tick_count t0 = tick_count::now();
int f = fib_par(n);
tick_count t1 = tick_count::now();
cout << "Fib = " << f << endl;
cout << "Time: " << std::fixed << (t1 - t0).seconds()
<< " sec." << endl;
return 0;
}

32
Граф задачи (Task graph)
Task A
Depth = 0

Refcount = 2

Task B

Task E

Depth = 1

Depth = 1

Refcount = 2

Refcount = 0

Task C

Task D

Depth = 2

Depth = 2

Refcount = 0

Refcount = 0

33
Планирование задач (Task scheduling)
 Каждый поток поддерживает дек готовых к выполнению
задач (deque, двусторонняя очередь)
 Планировщик использует комбинированный алгоритма
на основе обход графа задач в ширину и глубину

Top:
Oldest task

Bottom:
Youngest
Task

Task E
Task D
34
Планирование задач (Task scheduling)
 Листовые узлы в графе задач – это задачи готовые
к выполнению (ready task, они не ожидают других)
 Потоки могу захватывать (steal) задачи из чужих деков
(с их верхнего конца)

Top:
Oldest task

Bottom:
Youngest
Task

Top:
Oldest task

Task E
Task D

Bottom:
Youngest
Task

35
Выбор задачи из дека
 Задача для выполнения выбирается одним из следующих
способов (в порядке уменьшения приоритета):
1. Выбирается задача, на которую возвращен указатель
методом execute предыдущей задачи

2. Выбирается задача с нижнего конца (bottom) дека потока
3. Выбирается первая задача из дека (с его верхнего конца)
случайно выбранного потока – work stealing

36
Помещение задачи в дек потока
Задачи помещаются в дек с его нижнего конца


В дек помещается задача порожденная методом spawn



Задача может быть направлена на повторное выполнение
методом task::recycle_to_reexecute



Задача имеет счетчик ссылок (reference count)
равный нулю – все дочерние задачи завершены

37
Потокобезопасные контейнеры
 Intel TBB предоставляет классы контейнеров
(concurrent containers), которые корректно могут
обновляться из нескольких потоков
 Для работы в многопоточной программе со стандартными
контейнерами STL доступ к ним необходимо защищать
блокировками (мьютексами)
 Особенности Intel TBB:
o при работе с контейнерами применяет алгоритмы
не требующие блокировок (lock-free algorithms)
o при необходимости блокируются лишь небольшие
участки кода контейнеров (fine-grained locking)
38
Потокобезопасные контейнеры
 concurrent_hash_map
 concurrent_vector
 concurrent_queue

39
concurrent_vector
void append(concurrent_vector<char> &vec,
const char *str)
{
size_t n = strlen(str) + 1;
std::copy(str, str + n,
vec.begin() + vec.grow_by(n));
}

 Метод grow_by(n) безопасно добавляет n элементов
к вектору concurrent_vector

40
Взаимные исключения (Mutual exclusion)
 Взаимные исключения (mutual exclusion) позволяют
управлять количеством потоков, одновременно
выполняющих заданный участок кода
 В Intel TBB взаимные исключения реализованы
средствами мьютексов (mutexes) и блокировок (locks)
 Мьютекс (mutex) – это объект синхронизации,
который в любой момент времени может быть захвачен
только одним потоком, остальные потоки ожидают его
освобождения

41
Свойства мьютексов Intel TBB
 Scalable
 Fair – справедливые мьютексы захватываются в порядке
обращения к ним потоков (даже если следующий поток
в очереди находится в состоянии сна; несправедливые
мьютексы могут быть быстрее)
 Recursive – рекурсивные мьютексы позволяют
потоку захватившему мьютекс повторно его получить
 Yield – при длительном ожидании мьютекса поток
периодически проверяет его текущее состояние и снимает
себя с процессора (засыпает, в GNU/Linux вызывается
sched_yield(), а в Microsoft Windows – SwitchToThread())
 Block – потока освобождает процессор до тех пор, пока
не освободится мьютекс (такие мьютексы рекомендуется
использовать при длительных ожиданиях)
42
Мьютексы Intel TBB
 spin_mutex – поток ожидающий освобождения мьютекса
выполняет пустой цикл ожидания (busy wait)

 spin_mutex рекомендуется использовать для защиты
небольших участков кода (нескольких инструкций)
 queuing_mutex – scalable, fair, non-recursive, spins in user space
 spin_rw_mutex – spin_mutex + reader lock
 mutex и recursive_mutex – это обертки
вокруг взаимных исключений операционной системы
(Microsoft Windows – CRITICAL_SECTION,
GNU/Linux – мьютексы библиотеки pthread)
43
Мьютексы Intel TBB
Mutex

Scalable

Fair

Recursive

Long
Wait

Size

mutex

OS dep.

OS dep.

No

Blocks

>= 3
words

recursive_mutex

OS dep.

OS dep.

Yes

Blocks

>= 3
words

spin_mutex

No

No

No

Yields

1 byte

queuing_mutex

Yes

Yes

No

Yields

1 word

spin_rw_mutex

No

No

No

Yields

1 word

queuing_rw_mutex

Yes

Yes

No

Yields

1 word

44
spin_mutex
ListNode *FreeList;
spin_mutex ListMutex;
ListNode *AllocateNode()
{
ListNode *node;
{
// Создать и захватить мьютекс (RAII)
spin_mutex::scoped_lock lock(ListMutex);
node = FreeList;
if (node)
FreeList = node->next;
} // Мьютекс автоматически освобождается
if (!node)
node = new ListNode()
return node;
}
45
spin_mutex
void FreeNode(ListNode *node)
{
spin_mutex::scoped_lock lock(ListMutex);
node->next = FreeList;
FreeList = node;
}
 Конструктор scoped_lock ожидает освобождения мьютекса ListMutex
 Структурный блок (операторные скобки {}) внутри AllocateNode
нужен для того, чтобы при выходе из него автоматически вызывался
деструктор класса scoped_lock, который освобождает мьютекс
 Программная идиома RAII – Resource Acquisition Is Initialization
(получение ресурса есть инициализация)
46
spin_mutex
ListNode *AllocateNode()
{
ListNode *node;
spin_mutex::scoped_lock lock;
lock.acquire(ListMutex);
node = FreeList;
if (node)
FreeList = node->next;
lock.release();
if (!node)
node = new ListNode();
return node;
}
 Если защищенный блок (acquire-release) сгенерирует
исключение, то release вызван не будет!
 Используйте RAII если в пределах критической секции
возможно возникновение исключительной ситуации

47
Атомарные операции (Atomic operations)
 Атомарная операция (Atomic operation) – это операций,
которая в любой момент времени выполняется только
одним потоком
 Атомарные операции намного “легче” мьютексов –
не требуют блокирования потоков
 TBB поддерживаем атомарные переменные
atomic<T> AtomicVariableName

48
Атомарные операции (Atomic operations)
Операции над переменной atomic<T> x
=x
- чтение значения переменной x
x=
- запись в переменную x значения и его возврат

 x.fetch_and_store(y)
x = y и возврат старого значения x
 x.fetch_and_add(y)
x += y и возврат старого значения x
 x.compare_and_swap(y, z)
если x = z, то x = y, возврат старого значения x
49
Атомарные операции (Atomic operations)
atomic<int> counter;

unsigned int GetUniqueInteger()
{
return counter.fetch_and_add(1);
}

50
Атомарные операции (Atomic operations)
atomic<int> Val;
int UpdateValue()
{
do {
v = Val;
newv = f(v);
} while(Val.compare_and_swap(newv, v) != v);
return v;
}

51
Аллокаторы памяти
 Intel TBB предоставляет два аллокатора
памяти (альтернативы STL std::allocator)

 scalable_allocator<T> – обеспечивает параллельное
выделение памяти нескольким потокам
 cache_aligned_allocator<T> – обеспечивает выделение
блоков памяти, выравненных на границу длины кешлинии (cacheline)
 Это позволяет избежать ситуации когда потоки на разных
процессорах пытаются модифицировать разные слова
памяти, попадающие в одну строку кэша, и как следствие,
постоянно перезаписываемую из памяти в кеш
52
Аллокаторы памяти
/* STL vector будет использовать аллокатор TBB */
std::vector<int, cache_aligned_allocator<int> > v;

53
Ссылки
 James Reinders. Intel Threading Building Blocks.
– O'Reilly, 2007. – 336p.
 Intel Threading Building Blocks Documentation //
http://software.intel.com/sites/products/documentation/docli
b/tbb_sa/help/index.htm

54

More Related Content

What's hot

Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMSergey Platonov
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Mikhail Kurnosov
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияAlexey Paznikov
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython Meetup
 
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Platonov Sergey
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Platonov Sergey
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
 
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Alexey Paznikov
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типовcorehard_by
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Mikhail Kurnosov
 
Семинар 7. Многопоточное программирование на OpenMP (часть 7)
Семинар 7. Многопоточное программирование на OpenMP (часть 7)Семинар 7. Многопоточное программирование на OpenMP (часть 7)
Семинар 7. Многопоточное программирование на OpenMP (часть 7)Mikhail Kurnosov
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...Alexey Paznikov
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о BoostSergey Platonov
 

What's hot (20)

Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)Семинар 11. Параллельное программирование на MPI (часть 4)
Семинар 11. Параллельное программирование на MPI (часть 4)
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.by
 
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
 
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типов
 
Векторизация кода (семинар 2)
Векторизация кода (семинар 2)Векторизация кода (семинар 2)
Векторизация кода (семинар 2)
 
Семинар 7. Многопоточное программирование на OpenMP (часть 7)
Семинар 7. Многопоточное программирование на OpenMP (часть 7)Семинар 7. Многопоточное программирование на OpenMP (часть 7)
Семинар 7. Многопоточное программирование на OpenMP (часть 7)
 
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о Boost
 

Similar to Лекция 8: Многопоточное программирование: Intel Threading Building Blocks

Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x IntroductionFedor Vompe
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийAndrey Akinshin
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийMikhail Shcherbakov
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonovComputer Science Club
 
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий ЛевановСтатический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий ЛевановYandex
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...Alexey Paznikov
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийAndrey Akinshin
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Yandex
 
Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?Yauheni Akhotnikau
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кодаTatyanazaxarova
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаAndrey Karpov
 
Rust: абстракции и безопасность, совершенно бесплатно
Rust: абстракции и безопасность, совершенно бесплатноRust: абстракции и безопасность, совершенно бесплатно
Rust: абстракции и безопасность, совершенно бесплатноOpen-IT
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Yandex
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Mikhail Kurnosov
 
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++. Часть 3. Когда в C# не хватает C++. Часть 3.
Когда в C# не хватает C++ . Часть 3. Mikhail Shcherbakov
 
Сложности микробенчмаркинга
Сложности микробенчмаркингаСложности микробенчмаркинга
Сложности микробенчмаркингаAndrey Akinshin
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухинcorehard_by
 

Similar to Лекция 8: Многопоточное программирование: Intel Threading Building Blocks (20)

Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x Introduction
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
 
Статический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий ЛевановСтатический и динамический полиморфизм в C++, Дмитрий Леванов
Статический и динамический полиморфизм в C++, Дмитрий Леванов
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
 
Продолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложений
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11
 
Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
ADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кодаADD 2011: Статический анализ Си++ кода
ADD 2011: Статический анализ Си++ кода
 
Rust: абстракции и безопасность, совершенно бесплатно
Rust: абстракции и безопасность, совершенно бесплатноRust: абстракции и безопасность, совершенно бесплатно
Rust: абстракции и безопасность, совершенно бесплатно
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Когда в C# не хватает C++ . Часть 3.
Когда в C# не хватает C++. Часть 3. Когда в C# не хватает C++. Часть 3.
Когда в C# не хватает C++ . Часть 3.
 
Сложности микробенчмаркинга
Сложности микробенчмаркингаСложности микробенчмаркинга
Сложности микробенчмаркинга
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
 

More from Mikhail Kurnosov

Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Mikhail Kurnosov
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Mikhail Kurnosov
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)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
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиMikhail Kurnosov
 
Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Mikhail Kurnosov
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Mikhail Kurnosov
 
Лекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеЛекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеMikhail Kurnosov
 
Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Mikhail Kurnosov
 

More from Mikhail Kurnosov (20)

Векторизация кода (семинар 3)
Векторизация кода (семинар 3)Векторизация кода (семинар 3)
Векторизация кода (семинар 3)
 
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
 
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
Лекция 7. Декартовы деревья (Treaps, дучи, дерамиды)
 
Лекция 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. Методы разработки алгоритмов
 
Лекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимостиЛекция 10. Графы. Остовные деревья минимальной стоимости
Лекция 10. Графы. Остовные деревья минимальной стоимости
 
Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)Семинар 10. Параллельное программирование на MPI (часть 3)
Семинар 10. Параллельное программирование на MPI (часть 3)
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
 
Лекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графеЛекция 9. Поиск кратчайшего пути в графе
Лекция 9. Поиск кратчайшего пути в графе
 
Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)Семинар 8. Параллельное программирование на MPI (часть 1)
Семинар 8. Параллельное программирование на MPI (часть 1)
 

Лекция 8: Многопоточное программирование: Intel Threading Building Blocks

  • 1. Лекция 8: Intel Threading Building Blocks (Multithreading programming) Курносов Михаил Георгиевич к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет телекоммуникаций и информатики http://www.mkurnosov.net
  • 2. Intel Threading Building Blocks  Intel Treading Building Blocks (TBB) – это кроссплатформенная библиотека шаблонов C++ для создания многопоточных программ  История развития: o o o o o o o o 2006 – Intel TBB v1.0 (Intel compiler only) 2007 – Intel TBB v2.0 (Open Source, GPLv2) 2008 – Intel TBB v2.1 (thread affinity, cancellation) 2009 – Intel TBB v2.2 (C++0x lambda functions) … 2011 – Intel TBB v4.0 2012 – Intel TBB v4.1 2013 – Intel TBB v.4.2 http://threadingbuildingblocks.org 2
  • 3. Intel Threading Building Blocks  Open Source Community Version GPL v2  Поддерживаемые операционные системы: o Microsoft Windows {XP, 7, Server 2008, …} o GNU/Linux + Android o Apple Mac OS X 10.7.4, … http://threadingbuildingblocks.org 3
  • 4. Состав Intel TBB  Алгоритмы: parallel_for, parallel_reduce, parallel_scan, parallel_while, parallel_do, parallel_pipeline, parallel_sort  Контейнеры: concurrent_queue, concurrent_vector, concurrent_hash_map  Аллокаторы памяти: scalable_malloc, scalable_free, scalable_realloc, scalable_calloc, scalable_allocator, cache_aligned_allocator  Мьютексы: mutex, spin_mutex, queuing_mutex, spin_rw_mutex, queuing_rw_mutex, recursive mutex  Атомарные операции: fetch_and_add, fetch_and_increment, fetch_and_decrement, compare_and_swap, fetch_and_store  Таймеры, планировщик задач 4
  • 5. Состав Intel TBB  Алгоритмы: parallel_for, parallel_reduce, parallel_scan, parallel_while, parallel_do, parallel_pipeline, parallel_sort  Контейнеры: concurrent_queue, concurrent_vector, concurrent_hash_map  Аллокаторы памяти: scalable_malloc, scalable_free, scalable_realloc, scalable_calloc, scalable_allocator, cache_aligned_allocator  Мьютексы: mutex, spin_mutex, queuing_mutex, spin_rw_mutex, queuing_rw_mutex, recursive mutex  Атомарные операции: fetch_and_add, fetch_and_increment, fetch_and_decrement, compare_and_swap, fetch_and_store  Task-based parallelism (fork-join) + work stealing 5
  • 6. Intel Threading Building Blocks  Intel TBB позволяет абстрагироваться от низкоуровневых потоков и распараллеливать программу в терминах параллельно выполняющихся задач (task parallelism)  Задачи TBB “легче” потоков операционной системы  Планировщик TBB использует механизм “work stealing” для распределения задач по потокам  Все компоненты Intel TBB определены в пространстве имен C++ (namespace) “tbb” 6
  • 7. Компиляция программ с Intel TBB GNU/Linux $ g++ –Wall –o prog ./prog.cpp –ltbb Microsoft Windows (Intel C++ Compiler) C:> icl /MD prog.cpp tbb.lib 7
  • 8. Intel TBB: Hello World! // // tbb_hello.cpp: TBB Hello World // #include <cstdio> #include <tbb/tbb.h> // Function object class MyTask { public: MyTask(const char *name): name_(name) {} void operator()() const { // Task code std::printf("Hello from task %sn", name_); } private: const char *name_; }; 8
  • 9. Intel TBB: Hello World! (продолжение) int main( ) { tbb::task_group tg; tg.run(MyTask("1")); tg.run(MyTask("2")); tg.wait(); // Spawn task // Spawn task // Wait tasks return 0; } 9
  • 10. Компиляция и запуск tbb_hello $ g++ -Wall -I~/opt/tbb/include -L~/opt/tbb/lib -o tbb_hello ./tbb_hello.cpp -ltbb $ ./tbb_hello Hello from task 2 Hello from task 1 10
  • 11. Инициализация библиотеки  Любой поток использующий алгоритмы или планировщик TBB должен иметь инициализированный объект tbb::task_scheduler_init  TBB >= 2.2 автоматически инициализирует планировщик  Явная инициализация планировщика позволяет:  управлять когда создается и уничтожается планировщик  устанавливать количество используемых потоков выполнения  устанавливать размер стека для потоков выполнения 11
  • 12. Инициализация библиотеки  Явная инициализация планировщика #include <tbb/task_scheduler_init.h> int main() { tbb::task_scheduler_init init; return 0; } 12
  • 13. Инициализация библиотеки  Конструктор класса task_scheduler_init принимает два параметра: task_scheduler_init(int max_threads = automatic, stack_size_type thread_stack_size = 0);  Допустимые значения параметра max_threads:  task_scheduler_init::automatic – количество потоков определяется автоматически  task_scheduler_init::deferred – инициализация откладывается до явного вызова метода task_scheduler_init::initialize(max_threads)  Положительное целое – количество потоков 13
  • 14. Инициализация библиотеки #include <iostream> #include <tbb/task_scheduler_init.h> int main() { int n = tbb::task_scheduler_init::default_num_threads(); for (int p = 1; p <= n; ++p) { // Construct task scheduler with p threads tbb::task_scheduler_init init(p); std::cout << "Is active = " << init.is_active() << std::endl; } return 0; } 14
  • 15. Распараллеливание циклов  В TBB реализованы шаблоны параллельных алгоритмов  parallel_for  parallel_reduce  parallel_scan  parallel_do  parallel_for_each  parallel_pipeline  parallel_sort  parallel_invoke 15
  • 16. parallel_for void saxpy(float a, float *x, float *y, size_t n) { for (size_t i = 0; i < n; ++i) y[i] += a * x[i]; }  parallel_for позволяет разбить пространство итерации на блоки (chunks), которые обрабатываются разными потоками  Требуется создать класс, в котором перегруженный оператор вызова функции operator() содержит код обработки блока итераций 16
  • 17. parallel_for #include #include #include #include #include <iostream> <tbb/task_scheduler_init.h> <tbb/tick_count.h> <tbb/parallel_for.h> <tbb/blocked_range.h> class saxpy_par { public: saxpy_par(float a, float *x, float *y): a_(a), x_(x), y_(y) {} void operator()(const blocked_range<size_t> &r) const { for (size_t i = r.begin(); i != r.end(); ++i) y_[i] += a_ * x_[i]; } private: float const a_; float *const x_; float *const y_; }; 17
  • 18. parallel_for int main() { float a = 2.0; float *x, *y; size_t n = 100000000; x = new float[n]; y = new float[n]; for (size_t i = 0; i < n; ++i) x[i] = 5.0; tick_count t0 = tick_count::now(); task_scheduler_init init(4); parallel_for(blocked_range<size_t>(0, n), saxpy_par(a, x, y), auto_partitioner()); tick_count t1 = tick_count::now(); cout << "Time: " << (t1 - t0).seconds() << " sec." << endl; delete[] x; delete[] y; return 0; } 18
  • 19. parallel_for int main() { Класс blocked_range(begin, end, grainsize) описывает одномерное  float a = 2.0; пространство итераций float *x, *y; size_t n = 100000000;  В Intel TBB доступно описание многомерных пространств итераций (blocked_range2d, ...) x = new float[n]; y = new float[n]; for (size_t i = 0; i < n; ++i) x[i] = 5.0; tick_count t0 = tick_count::now(); task_scheduler_init init(4); parallel_for(blocked_range<size_t>(0, n), saxpy_par(a, x, y), auto_partitioner()); tick_count t1 = tick_count::now(); cout << "Time: " << (t1 - t0).seconds() << " sec." << endl; delete[] x; delete[] y; return 0; } 19
  • 20. affinity_partitioner int main() { // ... static affinity_partitioner ap; parallel_for(blocked_range<size_t>(0, n), saxpy_par(a, x, y), ap); // ... return 0; }  Класс affinity_partitioner запоминает какими потоками выполнялись предыдущие итерации и пытается распределять блоки итераций с учетом этой информации – последовательные блоки назначаются на один и тот же поток для эффективного использования кеш-памяти 20
  • 21. parallel_for (C++11 lambda expressions) int main() { // ... x = new float[n]; y = new float[n]; for (size_t i = 0; i < n; ++i) x[i] = 5.0; tick_count t0 = tick_count::now(); parallel_for(blocked_range<size_t>(0, n), [=](const blocked_range<size_t>& r) { for (size_t i = r.begin(); i != r.end(); ++i) y[i] += a * x[i]; } ); tick_count t1 = tick_count::now(); cout << "Time: " << (t1 - t0).seconds() << " sec." << endl; delete[] x; delete[] y; return 0; } 21
  • 22. parallel_for (C++11 lambda expressions) int main() Анонимная функция (лямбда-функция, С++11) {  [=] – захватить все автоматические переменные // ...  (const blocked_range …) – аргументы функции x = new float[n];  { ... } – код функции y = new float[n]; for (size_t i = 0; i < n; ++i) x[i] = 5.0; tick_count t0 = tick_count::now(); parallel_for(blocked_range<size_t>(0, n), [=](const blocked_range<size_t>& r) { for (size_t i = r.begin(); i != r.end(); ++i) y[i] += a * x[i]; } ); tick_count t1 = tick_count::now(); cout << "Time: " << (t1 - t0).seconds() << " sec." << endl; delete[] x; delete[] y; return 0; } 22
  • 23. parallel_reduce float reduce(float *x, size_t n) { float sum = 0.0; for (size_t i = 0; i < n; ++i) sum += x[i]; return sum; }  parallel_reduce позволяет распараллеливать циклы и выполнять операцию редукции 23
  • 24. parallel_reduce class reduce_par { public: float sum; void operator()(const blocked_range<size_t> &r) { float sum_local = sum; float *xloc = x_; size_t end = r.end(); for (size_t i = r.begin(); i != end; ++i) sum_local += xloc[i]; sum = sum_local; } // Splitting constructor: вызывается при порождении новой задачи reduce_par(reduce_par& r, split): sum(0.0), x_(r.x_) {} // Join: объединяет результаты двух задач (текущей и r) void join(const reduce_par& r) {sum += r.sum;} reduce_par(float *x): sum(0.0), x_(x) {} private: float *x_; }; 24
  • 25. parallel_reduce int main() { size_t n = 10000000; float *x = new float[n]; for (size_t i = 0; i < n; ++i) x[i] = 1.0; tick_count t0 = tick_count::now(); reduce_par r(x); parallel_reduce(blocked_range<size_t>(0, n), r); tick_count t1 = tick_count::now(); cout << "Reduce: " << std::fixed << r.sum << "n"; cout << "Time: " << (t1 - t0).seconds() << " sec." << endl; delete[] x; return 0; } 25
  • 26. parallel_sort void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp);  parallel_sort позволяет упорядочивать последовательности элементов  Применяется детерминированный алгоритм нестабильной сортировки с трудоемкостью O(nlogn) – алгоритм не гарантирует сохранения порядка следования элементов с одинаковыми ключами 26
  • 27. parallel_sort #include <cstdlib> #include <tbb/parallel_sort.h> using namespace std; using namespace tbb; int main() { size_t n = 10; float *x = new float[n]; for (size_t i = 0; i < n; ++i) x[i] = static_cast<float>(rand()) / RAND_MAX * 100; parallel_sort(x, x + n, std::greater<float>()); delete[] x; return 0; } 27
  • 28. Планировщик задач (Task scheduler)  Intel TBB позволяет абстрагироваться от реальных потоков операционной системы и разрабатывать программу в терминах параллельных задач (task-based parallel programming)  Запуск TBB-задачи примерно в 18 раз быстрее запуска потока POSIX в GNU/Linux (в Microsoft Windows примерно в 100 раз быстрее)  В отличии от планировщика POSIX-потоков в GNU/Linux планировщик TBB реализует “не справедливую” (unfair) политику распределения задач по потокам 28
  • 29. Числа Фибоначчи: sequential version int fib(int n) { if (n < 2) return n; return fib(n - 1) + fib(n - 2); } 29
  • 30. Числа Фибоначчи: parallel version int fib_par(int n) { int val; fibtask& t = *new(task::allocate_root()) fibtask(n, &val); task::spawn_root_and_wait(t); return val; }  allocate_root выделяет память под корневую задачу (task) класса fibtask  spawn_root_and_wait запускает задачу на выполнение и ожидает её завершения 30
  • 31. Числа Фибоначчи: parallel version class fibtask: public task { public: const int n; int* const val; fibtask(int n_, int* val_): n(n_), val(val_) {} }; task* execute() { if (n < 10) { *val = fib(n); // Use sequential version } else { int x, y; fibtask& a = *new(allocate_child()) fibtask(n - 1, &x); fibtask& b = *new(allocate_child()) fibtask(n - 2, &y); // ref_count: 2 children + 1 for the wait set_ref_count(3); spawn(b); spawn_and_wait_for_all(a);  spawn запускает задачу на выполнение *val = x + y; и не ожидает её завершения }  spawn_and_wait_for_all – запускает return NULL; задачу и ожидает завершения всех } дочерних задач 31
  • 32. Числа Фибоначчи: parallel version int main() { int n = 42; tick_count t0 = tick_count::now(); int f = fib_par(n); tick_count t1 = tick_count::now(); cout << "Fib = " << f << endl; cout << "Time: " << std::fixed << (t1 - t0).seconds() << " sec." << endl; return 0; } 32
  • 33. Граф задачи (Task graph) Task A Depth = 0 Refcount = 2 Task B Task E Depth = 1 Depth = 1 Refcount = 2 Refcount = 0 Task C Task D Depth = 2 Depth = 2 Refcount = 0 Refcount = 0 33
  • 34. Планирование задач (Task scheduling)  Каждый поток поддерживает дек готовых к выполнению задач (deque, двусторонняя очередь)  Планировщик использует комбинированный алгоритма на основе обход графа задач в ширину и глубину Top: Oldest task Bottom: Youngest Task Task E Task D 34
  • 35. Планирование задач (Task scheduling)  Листовые узлы в графе задач – это задачи готовые к выполнению (ready task, они не ожидают других)  Потоки могу захватывать (steal) задачи из чужих деков (с их верхнего конца) Top: Oldest task Bottom: Youngest Task Top: Oldest task Task E Task D Bottom: Youngest Task 35
  • 36. Выбор задачи из дека  Задача для выполнения выбирается одним из следующих способов (в порядке уменьшения приоритета): 1. Выбирается задача, на которую возвращен указатель методом execute предыдущей задачи 2. Выбирается задача с нижнего конца (bottom) дека потока 3. Выбирается первая задача из дека (с его верхнего конца) случайно выбранного потока – work stealing 36
  • 37. Помещение задачи в дек потока Задачи помещаются в дек с его нижнего конца  В дек помещается задача порожденная методом spawn  Задача может быть направлена на повторное выполнение методом task::recycle_to_reexecute  Задача имеет счетчик ссылок (reference count) равный нулю – все дочерние задачи завершены 37
  • 38. Потокобезопасные контейнеры  Intel TBB предоставляет классы контейнеров (concurrent containers), которые корректно могут обновляться из нескольких потоков  Для работы в многопоточной программе со стандартными контейнерами STL доступ к ним необходимо защищать блокировками (мьютексами)  Особенности Intel TBB: o при работе с контейнерами применяет алгоритмы не требующие блокировок (lock-free algorithms) o при необходимости блокируются лишь небольшие участки кода контейнеров (fine-grained locking) 38
  • 40. concurrent_vector void append(concurrent_vector<char> &vec, const char *str) { size_t n = strlen(str) + 1; std::copy(str, str + n, vec.begin() + vec.grow_by(n)); }  Метод grow_by(n) безопасно добавляет n элементов к вектору concurrent_vector 40
  • 41. Взаимные исключения (Mutual exclusion)  Взаимные исключения (mutual exclusion) позволяют управлять количеством потоков, одновременно выполняющих заданный участок кода  В Intel TBB взаимные исключения реализованы средствами мьютексов (mutexes) и блокировок (locks)  Мьютекс (mutex) – это объект синхронизации, который в любой момент времени может быть захвачен только одним потоком, остальные потоки ожидают его освобождения 41
  • 42. Свойства мьютексов Intel TBB  Scalable  Fair – справедливые мьютексы захватываются в порядке обращения к ним потоков (даже если следующий поток в очереди находится в состоянии сна; несправедливые мьютексы могут быть быстрее)  Recursive – рекурсивные мьютексы позволяют потоку захватившему мьютекс повторно его получить  Yield – при длительном ожидании мьютекса поток периодически проверяет его текущее состояние и снимает себя с процессора (засыпает, в GNU/Linux вызывается sched_yield(), а в Microsoft Windows – SwitchToThread())  Block – потока освобождает процессор до тех пор, пока не освободится мьютекс (такие мьютексы рекомендуется использовать при длительных ожиданиях) 42
  • 43. Мьютексы Intel TBB  spin_mutex – поток ожидающий освобождения мьютекса выполняет пустой цикл ожидания (busy wait)  spin_mutex рекомендуется использовать для защиты небольших участков кода (нескольких инструкций)  queuing_mutex – scalable, fair, non-recursive, spins in user space  spin_rw_mutex – spin_mutex + reader lock  mutex и recursive_mutex – это обертки вокруг взаимных исключений операционной системы (Microsoft Windows – CRITICAL_SECTION, GNU/Linux – мьютексы библиотеки pthread) 43
  • 44. Мьютексы Intel TBB Mutex Scalable Fair Recursive Long Wait Size mutex OS dep. OS dep. No Blocks >= 3 words recursive_mutex OS dep. OS dep. Yes Blocks >= 3 words spin_mutex No No No Yields 1 byte queuing_mutex Yes Yes No Yields 1 word spin_rw_mutex No No No Yields 1 word queuing_rw_mutex Yes Yes No Yields 1 word 44
  • 45. spin_mutex ListNode *FreeList; spin_mutex ListMutex; ListNode *AllocateNode() { ListNode *node; { // Создать и захватить мьютекс (RAII) spin_mutex::scoped_lock lock(ListMutex); node = FreeList; if (node) FreeList = node->next; } // Мьютекс автоматически освобождается if (!node) node = new ListNode() return node; } 45
  • 46. spin_mutex void FreeNode(ListNode *node) { spin_mutex::scoped_lock lock(ListMutex); node->next = FreeList; FreeList = node; }  Конструктор scoped_lock ожидает освобождения мьютекса ListMutex  Структурный блок (операторные скобки {}) внутри AllocateNode нужен для того, чтобы при выходе из него автоматически вызывался деструктор класса scoped_lock, который освобождает мьютекс  Программная идиома RAII – Resource Acquisition Is Initialization (получение ресурса есть инициализация) 46
  • 47. spin_mutex ListNode *AllocateNode() { ListNode *node; spin_mutex::scoped_lock lock; lock.acquire(ListMutex); node = FreeList; if (node) FreeList = node->next; lock.release(); if (!node) node = new ListNode(); return node; }  Если защищенный блок (acquire-release) сгенерирует исключение, то release вызван не будет!  Используйте RAII если в пределах критической секции возможно возникновение исключительной ситуации 47
  • 48. Атомарные операции (Atomic operations)  Атомарная операция (Atomic operation) – это операций, которая в любой момент времени выполняется только одним потоком  Атомарные операции намного “легче” мьютексов – не требуют блокирования потоков  TBB поддерживаем атомарные переменные atomic<T> AtomicVariableName 48
  • 49. Атомарные операции (Atomic operations) Операции над переменной atomic<T> x =x - чтение значения переменной x x= - запись в переменную x значения и его возврат  x.fetch_and_store(y) x = y и возврат старого значения x  x.fetch_and_add(y) x += y и возврат старого значения x  x.compare_and_swap(y, z) если x = z, то x = y, возврат старого значения x 49
  • 50. Атомарные операции (Atomic operations) atomic<int> counter; unsigned int GetUniqueInteger() { return counter.fetch_and_add(1); } 50
  • 51. Атомарные операции (Atomic operations) atomic<int> Val; int UpdateValue() { do { v = Val; newv = f(v); } while(Val.compare_and_swap(newv, v) != v); return v; } 51
  • 52. Аллокаторы памяти  Intel TBB предоставляет два аллокатора памяти (альтернативы STL std::allocator)  scalable_allocator<T> – обеспечивает параллельное выделение памяти нескольким потокам  cache_aligned_allocator<T> – обеспечивает выделение блоков памяти, выравненных на границу длины кешлинии (cacheline)  Это позволяет избежать ситуации когда потоки на разных процессорах пытаются модифицировать разные слова памяти, попадающие в одну строку кэша, и как следствие, постоянно перезаписываемую из памяти в кеш 52
  • 53. Аллокаторы памяти /* STL vector будет использовать аллокатор TBB */ std::vector<int, cache_aligned_allocator<int> > v; 53
  • 54. Ссылки  James Reinders. Intel Threading Building Blocks. – O'Reilly, 2007. – 336p.  Intel Threading Building Blocks Documentation // http://software.intel.com/sites/products/documentation/docli b/tbb_sa/help/index.htm 54