Объектно-ориентированное программирование. Лекции 15 и...

25
ВВЕДЕНИЕ В МУЛЬТИПРОГРАММИРОВАНИЕ часть 2 ЛЕКЦИЯ №15-16

Transcript of Объектно-ориентированное программирование. Лекции 15 и...

ВВЕДЕНИЕВМУЛЬТИПРОГРАММИРОВАНИЕчасть2ЛЕКЦИЯ№15-16

Условнаяпеременнаяпримитивсинхронизации,обеспечивающийблокированиеодногоилинесколькихпотоковдомоментапоступлениясигналаотдругогопотокаовыполнениинекоторогоусловияилидоистечениямаксимальногопромежуткавремениожидания.Условныепеременныеиспользуютсявместесассоциированныммьютексом иявляютсяэлементомнекоторыхвидовмониторов.

Монитор

thread

wait

thread

notifyAll

thread

wait

thread

wait

thread

wait

Условныепеременные <condition_variable>Example116_CondVariable1condition_variableтребуетотлюбогопотокапередожиданиемсначалавыполнитьstd::unique_lock

1. Долженбытьхотябыодинпоток,ожидающий,покакакое-тоусловиестанетистинным.Ожидающийпотокдолженсначалавыполнитьunique_lock.

2. Долженбытьхотябыодинпоток,сигнализирующийотом,чтоусловиесталоистинным.Сигналможетбытьпосланспомощьюnotify_one(),приэтомбудетразблокированодин(любой)потокизожидающих,илиnotify_all(),чторазблокируетвсеожидающиепотоки.

3. Ввидунекоторыхсложностейприсозданиипробуждающегоусловия,котороеможетбытьпредсказуемыхвмногопроцессорныхсистемах,могутпроисходитьложныепробуждения(spurious wakeup).Этоозначает,чтопотокможетбытьпробужден,дажееслиниктонесигнализировалусловнойпеременной.Поэтомунеобходимоещепроверять,вернолиусловиепробуждениеужепослето,какпотокбылпробужден.

ЗапускаемцепочкузаданийExample117_CondVariable2

Процесс1

Процесс2

ОжидаетусловнойПеременнойвследующемпотоке

Процесс3

ОжидаетусловнойПеременнойвследующемпотоке

ЗаконАмдалаДжинАмдал(Gene Amdahl)- одинизразработчиковвсемирноизвестнойсистемы IBM360в1967годупредложилформулу,отражающуюзависимостьускорениявычислений,достигаемогонамногопроцессорнойВС,какотчислапроцессоров,такиотсоотношениямеждупоследовательнойираспараллеливаемойчастямипрограммы.ПроблемарассматриваласьАмдаломисходяизположения,чтообъемрешаемой задачи(рабочаянагрузка- числовыполняемыхопераций)сизменением числапроцессоров,участвующихвеерешении, остаетсянеизменным.

Пустьf - доляопераций,которыедолжнывыполнятьсяпоследовательнооднимизпроцессорови1-f - доля,приходящаясянараспараллеливаемуючастьпрограммы.Тогдаускорение,котороеможетбытьполученонаВСиз n процессоров,посравнениюсоднопроцессорнымрешениемнебудетпревышатьвеличины:

S(n)=T(1)/T(n)=1/[f+(1-f)/n].

Например,еслиполовинаоперацийподлежитраспараллеливаниюна4машинах, тоускорениеравно:

S(4)=1/(0.5+0.5/4)=1.6т.е.Тольковполторараза!

Пример организациивычисленийExample103_Zookeeper

Проблемаблокировок1. Взаимоблокировки(Deadlocks)2. Надежность— вдругвладелецблокировкипомрет?3. Performance◦ Параллелизмавкритическойсекциинет!◦ Владелецблокировкиможетбытьвытеснен

планировщиком

Неблокирующиеалгоритмы1. Безпрепятствий(Obstruction-Free)— потоксовершает

прогресс,еслиневстречаетпрепятствийсостороныдругихпотоков

2. Безблокировок(Lock-Free)— гарантируетсясистемныйпрогрессхотябыодногопотока

3. Безожидания(Wait-Free)— каждаяоперациявыполняетсязафиксированноечислошагов,независящееотдругихпотоков

АтомарныеоперацииАтомарностьозначаетнеделимостьоперации.Этозначит,чтониодинпотокнеможетувидетьпромежуточноесостояниеоперации,оналибовыполняется,либонет.

Напримероперация«++»неявляетсяатомарной:

int x = 0;

++x;

Транслируетсявассемблерныйкод,примернотак:

013C5595 mov eax,dword ptr [x]

013C5598 add eax,1

013C559B mov dword ptr [x],eax

АтомарныетипыC++#include<atomic>

std::atomic_bool //bool

std::atomic_char //char

std::atomic_schar //signed char

std::atomic_uchar //unsigned char

std::atomic_int //int

std::atomic_uint //unsigned int

std::atomic_short //short

std::atomic_ushort //unsigned short

std::atomic_long //long

std::atomic_ulong //unsigned long

std::atomic_llong //long long

std::atomic_ullong //unsigned long long

std::atomic_char16_t //char16_t

std::atomic_char32_t //char32_t

std::atomic_wchar_t //wchar_t

std::atomic_address //void*

CAS-операции1. CAS— compare-and-set,compare-and-

swap◦ bool compare_and_set(◦ int*адрес_переменной ,◦ int староезначение ,◦ int новоезначение)

2. ✔ Возвращает признакуспешностиоперации установки значения

3. ✔ Атомарнана уровнепроцессора

1. Являетсяаппаратнымпримитивом

2. Возможностьпродолжениязахватапримитивабезобязательногопереходаврежим«ожидания»

3. Меньшевероятностьвозникновенияблокировкииз-заболеемелкойоперации

4. Болеебыстрая

CASLoop— типичный паттернприменения1. ПрочитатьзначениеA изпеременнойV2. Взятькакое-тоновоезначениеB дляV3. ИспользоватьCASдляатомарногоизмененияV изA вB дотех

пор,покадругиепотокименяютзначениеV вовремяэтогопроцесса

Основныеоперацииload() //Прочитать текущее значение

store() //Установить новое значение

exchange() //Установить новое значение и вернуть предыдущее

compare_exchange_weak() // см. следующий слайд

compare_exchange_strong() // compare_exchange_weak в цикле

fetch_add() //Аналог оператора ++

fetch_or() //Аналог оператора --

is_lock_free() //Возвращает true, если операции на данном типе неблокирующие

Методatomic::compare_exchange_weakbool compare_exchange_weak( Ty& Exp, Ty Value)

Сравниваетзначениякоторыехранитсяв*this сExp.

• Еслизначенияравнытооперациязаменяетзначение,котораяхранитсяв*this наVal(*this=val),спомощьюоперацииread-modify-write.

• Еслизначениянеравны,тооперацияиспользуетзначение,котораяхранитсяв*this,чтобызаменитьExp (exp=this).

ПростойпримерExample120_CASSimple

1.class Counter {2.private:3. std::atomic_int value_a;4.public:5. Counter() : value_a(0) { }6. int get_a() {7. return value_a.load();8. }9. int increment_atomic() {10. int v = value_a.load();11. while (!value_a.compare_exchange_weak(v, v + 1));12. return value_a.load();13. }14.};

Потокобезопасный StackExample119_CASvoid push(const T& data)

{

node* new_node = new node(data, head.load());

while (!head.compare_exchange_weak(

new_node->next,

new_node));

}

Недостатки CAS1. CASзаставляетпотоки,которыееговызывают,

работатьвусловияхсоревнования(contention)2. Большеcontention =большебесполезныхциклов

процессора,тратапроцессорноговремени3. НаписаниекорректныхибыстрыхалгоритмовнаCAS

требуетспециальнойподготовки

Лямбдавыражения

LambdaExample121_LambdaЛямбда-выражениявC++— этократкаяформазаписианонимныхфункторов.

Например:

[](int _n){cout <<_n<<"";}

Соответствует:

class MyLambda{public:void operator ()(int _x)const {cout <<_x<<"";}

};

ЛямбдафункциимогутвозвращатьзначенияExample122_Lambda2Вслучае,есливлямбда-функциитолькоодиноператорreturnтотипзначенияможнонеуказывать.Еслинесколько,тонужноявноуказать.[] (int i) -> double

{

if (i < 5)

return i + 1.0;

else if (i % 2 == 0)

return i / 2.0;

else

return i * i;

}

ЗахватпеременныхизвнешнегоконтекстаExample123_Lambda3[] // без захвата переменных из внешней области видимости

[=] // все переменные захватываются по значению

[&] // все переменные захватываются по ссылке

[this] // захват текущего класса

[x, y] // захват x и y по значению

[&x, &y] // захват x и y по ссылке

[in, &out] // захват in по значению, а out — по ссылке

[=, &out1, &out2] // захват всех переменных по значению, кроме out1 и out2,

// которые захватываются по ссылке

[&, x, &y] // захват всех переменных по ссылке, кроме x…

Взболтатьнонесмешивать: lambda+std::asyncExample124_LambdaAsync

1.// создаем vector для результатов вычислений2. std::vector<std::future < double>> results;

3.// запускаем подзадачи с помощью std::async4. for (int i = 0; i < 100; i++)5. results.push_back(std::async([i]() -> double {6. double result = 0;7. for(int j=1;j<=STEP;j++) result+= std::log10(i*STEP+j);8. return result;9. }));

10.// собираем результаты11. for (auto &i : results) val+=i.get();

Генерациялямбда-выраженийExample125_LambdaGenerationНачинаясостандартаC++11шаблонныйклассstd::function являетсяполиморфнойоберткойфункцийдляобщегоиспользования.Объектыклассаstd::function могутхранить,копироватьивызыватьпроизвольныевызываемыеобъекты- функции,лямбда-выражения,выражениясвязыванияидругиефункциональныйобъекты.Говорявобщем,влюбомместе,гденеобходимоиспользоватьуказательнафункциюдляеёотложенноговызова,илидлясозданияфункцииобратноговызова,вместонегоможетбытьиспользованstd::function,которыйпредоставляетпользователюбольшуюгибкостьвреализации.

Определениекласса

template<class> class function; // undefined

template<class R, class... ArgTypes> classfunction<R(ArgTypes...)>;

Чтоещепочитать?C++ConcurrencyinActionPracticalMultithreadingAnthonyWilliams

February,2012|528pagesISBN:9781933988771

Разныеблоги,например:

http://habrahabr.ru/post/182610/

Спасибо!ВСЕИДЕМНАПЕРЕРЫВ