2. Lygiagretus programavimas sudėtingas Padaromas tik labiau patyrusių programuotojų Lygiagretūs šablonai nėra paplitę, gerai žinomi ir lengvai įgyvendinami Krūva galimų problemų: Gijų varžymaisi (races) Mirties taškas (deadlock) Gyvas taškas (livelock) Pamiršti pranešimai (lost event notifications) …
5. Parallel Patterns Library (PPL) Veikia kaip ConcurrencyRuntimekomponentas Abstrakcijos lygis tarp programos ir gijų mechanizmo Lengvas panaudojimas Galimybė plėstis (scalability)
6. Struktūrinis ir nestruktūrinis lygiagretumas Struktūrinis: Lygiagretus kodas pradedamas ir baigiamas viename kontekste Užduotis negali baigtis, kol nesibaigia jos dukterinės užduotys Didesnis našumas Nestruktūrinis: Leidžia užduotį pradėti ir baigti ar jai laukti skirtinguose kontekstuose Lankstesnis
7. PPL sudėtis Lygiagrečios užduotys (Task Parallelism) Kelios užduotys lygiagrečiai Lygiagretūs algoritmai (Parallel Algorithms) Bendriniai algoritmai darbui su duomenų rinkiniais Lygiagrečios talpyklos ir objektai (Parallel containers & objects) Bendrinės talpyklos/objektai saugiam darbui su jų viduje esančiais elementais
8. PPL: Užduotys Užduotis (Task)–skaičiavimas, kuris viduje gali būti išskaidytas task_handle klasė Užduočių grupė (Task group) – užduočių, formuojančių loginius skaičiavimus, grupė task_group klasė structured_task_group klasė
10. Užduotys. Kada/kur naudoti? Rekursiniuose metoduose Norint išskaidyti darbą į atskiras dalis Norėdami aprašysi savo lygiagretų algoritmą, kai neužtenka standartinių PPL algoritmų. Jei galime, naudojame pastaruosius
12. PPL: Algoritmai PPL Algoritmai panašūs į STL algoritmus Išnaudoja jau esamą ConcurrencyRuntimefunkctionalumą Algoritmai: parallel_for parallel_for(begin,end,step,[](inti){ …}); parallel_for_each parallel_for(v.begin(),v.end(),[](inti){ … }); parallel_invoke parallel_invoke([]{…},[]{…},[]{…},…,[]{…});
13. parallel_for() Kartoja tą pačią užduotį lygiagrečiai Optimaliai išskaido užduotis lygiagrečiam vykdymui Balansuoja tarp išskaidytų dalių priklausomai nuo apkrovų. Užduočių vykdymas neturi numatytos tvarkos Argumentai: Pradinė reikšmė, galinė reikšmė, žingsnis, funkcija Pradinė reikšmė, galinė reikšmė, funkcija (Žingsnis tokiu atveju pagal nutylėjimą = 1)
14. for() parallel_for() Daugelį for ciklų galima pakeisti parallel_for, tačiau: Ciklo indeksas (_Index_type) gali būti tik sveiko tipo Iteracija gali vykti tik į priekį (jei žingsnis (_Step) mažesnis nei 1, gauna klaida) Pabaigos sąlyga turi būti konkreti. Iteracija baigiama, kai iteracijos kintamasis pasiekia reikšmę _Last
15. parallel_for_each() Lygiagrečiai atlieka veiksmus iteruojamoje talpykloje (tarkim tokioje, kokias suteikia STL) Naudoja tą pačią užduočių skaidymo logiką kaip ir parallel_for Užduočių vykdymas taip pat neturi numatytos tvarkos Veikia tiek su einančiais į priekį (forward) iteratoriais, tiek su atsitiktinio priėjimo (randomaccess) iteratoriais. Su pastaraisiais greičiau.
16. parallel_invoke() Vykdo užduočių rinkinį paraleliai. Nebaigia darbo tol, kol darbo nebaigia visos lygiagrečiai vykdomos užduotys Priima nuo 2 iki 10 parametrų – funkcijų, kurias vykdys. Kiekviena perduodama funkcija neturi turėti parametrų. Užduočių vykdymas taip pat neturi numatytos tvarkos Patogus, kai norima vykdyti keletą nepriklausomų užduočių lygiagrečiai
20. concurent_vector Naudojimas panašus į STL bibliotekos vector klasės Papildymas, paėmimas, iteracija veikia lygiagrečiai Elementus pridėti galima tik į galą (nėra insert() metodo) Galima pašalinti visus elementus su clear() metodu. Šalinti vieno elemento negalima. Nesaugo savo elementų atmintyje iš eilės, tad negalima atlikti kai kurių masyvam būdingų operacijų Galima keisti dydį su grow_by() ir grow_to_at_least() (atitikmuo resize())
21. concurent_queue Naudojimas panašus į STL bibliotekos queue() klasės Leidžia pasiekti pirmą (dequeue) ir paskutinį (enqueue) elementus. Nėra front() ir pop() metodų. Vietoj jų – try_pop() Nėraback() metodo, tad negalima kreiptis į eilės galą Metodu empty() galima patikrinti ar eilė tuščia. Iteracija ir bei dydžio gavimas nėra pritaikyti lygiagrečiam veikimu
22. combinable Suteikia daug kartų naudojamą saugyklą gijoje, iš kurių rezultatai sujungiami į bendrą Naudingas, kai reikia kažkokiu resursu dalintis keliose gijose/užduotyse Nebereikia naudoti papildomų priemonių (tarkim mutex) combinable<int>sum; parallel_for_each(a.begin(),a.end(),[&](inti){ sum.local()+=(is_prime(i)?i:0); }); prime_sum=sum.combine(plus<int>());
23. PPL: Lygiagretaus darbo atšaukimas (sustabdymas) tg1 t1 t2 t3 tg2 Užduotis Užduočių grupė t4 t5
24. Lygiagrečių užduočių stabdymas Du būdai sustabdyti: task_group::cancel() ir structured_task_group::cancel() Atšaukia užduočių grupę ir visas dukterines užduočių grupes (iš viršaus į apačią) Efektyvesnis Išimties (exception) išmetimas užduoties darbo funkcijoje. Atšaukinėja kiekvieną užduočių grupę atskirai (iš apačios į viršų)
25. Lygiagrečių algoritmų stabdymas Kadangi PPL lygiagretūs algoritmai veikia lygiagrečių užduočių pagrindu, jiems sustabdyti (atšaukti) galime naudoti tuos pačios būdus. structured_task_grouptg; task_group_statusstatus=tg.run_and_wait([&]{ parallel_for(0,100,[&](inti){ // Atšaukiam užduotį, kai pasiekiam 50 if(i==50) { tg.cancel(); }else{ // Normalus darbas } }); });
26. (NE)stabdom Lygiagretaus darbo stabdymas (atšaukimas) tinkamas naudoti, kai kiekviena susijusios grupės užduotis darbą gali baigti savo laiku Yra atvejų, kai lygiagrečios užduočių grupės sustabdymas nėra geras sprendimas: Užduotis, kuri atblokuoja kitą aktyvią užduotį, nėra startavusi Ši užduotis nestartuoja, jei grupė atšaukiama Galimas mirties taškas (deadlock)