1: Многопоточные приложения
2: Concurrency Несколько вычислительных ядер процессора позволяют выполнять несколько задач одновременно. Одно ядро процессора может выполнять несколько задач, только переключаясь между ними.
3: Два вида многозадачности Multiple processes
4: За чем применять многозадачность? Разделение программы на независимые части. Один процесс выполняет одну задачу (например, взаимодействие с пользователем), а другой – другую (например, вычисления). Для увеличения производительности. Увеличение числа параллельных процессов не всегда приводит к ускорению программы.
5: Hello World! CPPExamples18 include include void hello() std::cout
6: Передаем объекты в поток CPPExamples19 std::uniqueptr – позволяет иметь только одну ссылку на объект. Его нельзя копировать. std::move – позволяет перемещать содержимое uniqueptr; void clearP(std::uniqueptr& ptr) … std::uniqueptr p(new BigObject(4096)); std::thread t(clearP,std::move(p));
7: Полезные функции std::thread::hardwareconcurrency() Возвращает количество Thread которые могут выполняться параллельно для данного приложения. std::thisthread::getid() Возвращает идентификатор потока. std::thisthread::sleepfor(std::chrono::milliseconds) Позволяет усыпить поток на время
8: Как дождаться завершения потока красиво? CPPExamples20 std::foreach – позволяет применять функцию к элементам коллекции template Function foreach(InputIterator first, InputIterator last, Function fn) while (first!last) fn (first); first; return fn; // or, since C11: return move(fn); std::memfn – делает из метода класса функцию, первый параметр которой объект класса
9: Проблемы работы с динамическими структурами данных в многопоточной среде При удалении элемента из связанного списка производится несколько операций: - удаление связи с предыдущим элементом - удаление связи со следующим элементом - удаление самого элемента списка Во время выполнения этих операций к этими элементами обращаться из других потоков нельзя!
10: Mutex CPPExamples23 Мьютекс — базовый элемент синхронизации и в С11 представлен в 4 формах в заголовочном файле : mutex обеспечивает базовые функции lock() и unlock() и не блокируемый метод trylock() recursivemutex может войти «сам в себя» timedmutex в отличие от обычного мьютекса, имеет еще два метода: trylockfor() и trylockuntil() recursivetimedmutex это комбинация timedmutex и recursivemutex
11: Потоко-безопасный Stack CPPExamples21 Классы «обертки» позволяют непротиворечиво использовать мьютекс в RAII-стиле с автоматической блокировкой и разблокировкой в рамках одного блока. Эти классы: lockguard когда объект создан, он пытается получить мьютекс (вызывая lock()), а когда объект уничтожен, он автоматически освобождает мьютекс (вызывая unlock()) uniquelock в отличие от lockguard, также поддерживает отложенную блокировку, временную блокировку, рекурсивную блокировку и использование условных переменных
12: Deadlock std::lockguard lock(a); std::lockguard lock(b);
13: Exceptions в многопоточной среде CPPExamples22 Исключения между потоками не передаются! Нужно устроить хранилище исключений, для того что бы их потом обработать!
14: Условные переменные CPPExamples24,25 conditionvariable требует от любого потока перед ожиданием сначала выполнить std::uniquelock conditionvariableany более общая реализация, которая работает с любым типом, который можно заблокировать Должен быть хотя бы один поток, ожидающий, пока какое-то условие станет истинным. Ожидающий поток должен сначала выполнить uniquelock. Должен быть хотя бы один поток, сигнализирующий о том, что условие стало истинным. Сигнал может быть послан с помощью notifyone(), при этом будет разблокирован один (любой) поток из ожидающих, или notifyall(), что разблокирует все ожидающие потоки. В виду некоторых сложностей при создании пробуждающего условия, которое может быть предсказуемых в многопроцессорных системах, могут происходить ложные пробуждения (spurious wakeup). Это означает, что поток может быть пробужден, даже если никто не сигнализировал условной переменной. Поэтому необходимо еще проверять, верно ли условие пробуждение уже после то, как поток был пробужден.
15: Lambda CPPExamples26 Лямбда-выражения в C — это краткая форма записи анонимных функторов. Например: (int n) cout
16: Лямбда функции могут возвращать значения CPPExamples27 В случае, если в лямбда-функции только один оператор return то тип значения можно не указывать. Если несколько, то нужно явно указать. (int i) - double if (i 5) return i 1. 0; else if (i 2 0) return i / 2. 0; else return i i;
17: Захват переменных из внешнего контекста CPPExamples28 // без захвата переменных из внешней области видимости // все переменные захватываются по значению & // все переменные захватываются по ссылке this // захват текущего класса x, y // захват x и y по значению &x, &y // захват x и y по ссылке in, &out // захват in по значению, а out — по ссылке , &out1, &out2 // захват всех переменных по значению, кроме out1 и out2, // которые захватываются по ссылке &, x, &y // захват всех переменных по ссылке, кроме x…
18: Генерация лямбда-выражений CPPExamples29 Начиная со стандарта C11 шаблонный класс std::function является полиморфной оберткой функций для общего использования. Объекты класса std::function могут хранить, копировать и вызывать произвольные вызываемые объекты - функции, лямбда-выражения, выражения связывания и другие функциональный объекты. Говоря в общем, в любом месте, где необходимо использовать указатель на функцию для её отложенного вызова, или для создания функции обратного вызова, вместо него может быть использован std::function, который предоставляет пользователю большую гибкость в реализации. Впервые данный класс появился в библиотеке Function в версии Boost 1. 23. 07. После его дальнейшей разработки, он был включен в стандарт расширения C TR1 и окончательно утвержден в С11. Определение класса template class function; // undefined template class function;
19: Атомарные операции Атомарность означает неделимость операции. Это значит, что ни один поток не может увидеть промежуточное состояние операции, она либо выполняется, либо нет. Например операция «» не является атомарной: int x 0; x; Транслируется в ассемблерный код, примерно так: 013C5595 mov eax,dword ptr x 013C5598 add eax,1 013C559B mov dword ptr x,eax
20: Атомарные типы C include std::atomicbool //bool std::atomicchar //char std::atomicschar //signed char std::atomicuchar //unsigned char std::atomicint //int std::atomicuint //unsigned int std::atomicshort //short std::atomicushort //unsigned short std::atomiclong //long std::atomiculong //unsigned long std::atomicllong //long long std::atomicullong //unsigned long long std::atomicchar16t //char16t std::atomicchar32t //char32t std::atomicwchart //wchart std::atomicaddress //void
21: Основные операции load() //Прочитать текущее значение store() //Установить новое значение exchange() //Установить новое значение и вернуть предыдущее compareexchangeweak() // см. следующий слайд compareexchangestrong() // compareexchangeweak в цикле fetchadd() //Аналог оператора fetchor() //Аналог оператора -- islockfree() //Возвращает true, если операции на данном типе неблокирующие
22: Метод atomic::compareexchangeweak bool compareexchangeweak( Ty& Exp, Ty Value) Сравнивает значения которые хранится в this с Exp. Если значения равны то операция заменяет значение, которая хранится в this на Val (thisval) , с помощью операции read-modify-write. Если значения не равны, то операция использует значение, которая хранится в this, чтобы заменить Exp (expthis).
23: Потокобезопасный Stack CPPExamples30 void push(const T& data) node newnode new node(data, head. load()); while (!head. compareexchangeweak( newnode-next, newnode));
24: Что еще почитать? C Concurrency in Action Practical Multithreading Anthony Williams February, 2012 528 pages ISBN: 9781933988771 Разные блоги, например: http://habrahabr. ru/post/182610/