Luentokalvot - Rinnakkaisuus
Transcription
Luentokalvot - Rinnakkaisuus
*x++=*y++ 815338A Ohjelmointikielten periaatteet 2014 - 2015 IX Rinnakkainen ohjelmointi *x++=*y++ Sisältö 1. 2. 3. 4. 5. 6. 7. Yleistä rinnakkaisuudesta Prosesseista ja säikeistä Rinnakkaisen ohjelman oikeellisuudesta Rinnakkaisuuden kontrollirakenteet Rinnakkaisuus Javassa Rinnakkaisuus C++-kielessä Rinnakkaisuus muissa ohjelmointikielissä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 2 *x++=*y++ IX.1. Yleistä rinnakkaisuudesta Peräkkäinen vs. Käskyt suoritetaan peräkkäin Yksikäsitteinen suorituspolku Deterministinen sama syöte, sama tulos aina Ari Vesanen, Tietojenkäsitttelytieteiden laitos Rinnakkainen Toimintoja suoritetaan rinnakkain Ei selvää suorituspolkua Epädeterministinen tulos voi riippua suoritusjärjestyksestä 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 3 *x++=*y++ IX.1.1. Rinnakkaisuuden tyypit Parallel programming Aito (fyysinen) rinnakkaisuus Vaatii useampia prosessoreja (tai ainakin ytimiä) Concurrent programming Rinnakkaisuus voi olla harhaa: suoritetaan yksi konekielinen käsky kerrallaan Toiminnot rinnakkain – looginen rinnakkaisuus Toimii yhdessä prosessorissa Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 4 *x++=*y++ IX.2. Prosesseista ja säikeistä IX.2.1. Prosessi Tapa ajaa useita ohjelmia rinnakkain yhdessä prosessorissa Oma muistialue Kommunikointi esim. putkilla Rinnakkainen suorittaminen aikajaolla Ominaisuudet riippuvat käyttöjärjestelmästä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 5 *x++=*y++ IX.2.2. Säikeet Prosessia kevyempiä Prosessi voidaan jakaa säikeisiin Säikeellä oma ohjelmalaskuri ja pino Säikeet jakavat prosessin muistialueen ja resurssit Käyttöjärjestelmissä standardi: Pthread (POSIX: IEEE 1003.1) Tässä monisäieohjelmointia Liittyy läheisemmin ohjelmointikieliin Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 6 *x++=*y++ IX.2.2.1 Säikeen elinkaari Uusi Käynnistys Ajettava/ Suorituksessa suoritus loppuu odotus ilmoitus sleep() sleep aika IO esto IO suoritus Kuollut suoritus loppuu Estetty Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 7 *x++=*y++ IX.3. Rinnakkaisen ohjelman oikeellisuudesta Rinnakkaisen ohjelman oikeellisuuskriteerit: Turvallisuus (safety) Oliot ja muuttujat pysyvät kunnossa Eloisuus (liveness) Kaikki aiotut operaatiot suoritetaan joskus Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 8 *x++=*y++ IX.3.1. Turvallisuus Ei-atomaarinen operaatio voi epäonnistua jos kaksi säiettä toimii yhtä aikaa Metodi voi toimia väärin jos sitä kutsutaan kahdesta säikeestä Säieturvallinen (thread safe): toimii millä tahansa kutsujärjestyksellä Muuttujan lukeminen ja arvon kirjoittaminen samanaikaisesti = Luku/Kirjoituskonflikti Muuttujan arvon kirjoittaminen samanaikaisesti kahdesta säikeestä= Kirjoitus/Kirjoituskonflikti Yleistermi kilpailutilanne (race condition) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 9 *x++=*y++ IX.3.2. Eloisuus Aiotut operaatiot suoritetaan – ei aikarajaa Reaaliaikainen ohjelmointi – asetetaan aikarajoja Turvallisuus ja eloisuus jossain määrin vastakkaisia Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 10 *x++=*y++ IX.3.3. Operaation epäonnistuminen Operaation suorittamatta jäämisen yleisin syy: odotetaan resurssin vapautumista, esimerkiksi Toinen säie on lukinnut suoritettavan metodin Metodi lukkiutuu odottaen toisen säikeen suorittamaa tapahtumaa Pysyvän epäonnitumisen syitä: Lukkiutuminen (deadlock) Säikeet ristiinlukitsevat metodit Nälkiintyminen (starvation) Säie ei saa lainkaan keskusyksiköltä ajoaikaa Voi johtua monista syistä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 11 *x++=*y++ IX.3.4. Synkronointi Säikeiden jaksottaminen niin, että ohjelman oikeellisuus varmistuu Kilpailun synkronointi (competition synchronization) Tarvitaan, kun kaksi säiettä yrittää toisistaan riippumatta käyttää jotakin resurssia Toteutus yleensä: Säie pyytää synkronointioliolta resurssin käyttöoikeutta, vapauttaa resurssin lopetettuaan operaationsa Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 12 *x++=*y++ IX.3.4. Synkronointi (2) Yhteistoiminnan synkronointi (cooperation synchronization). Tarvitaan, kun jonkin säikeen A operaation suorittaminen riippuu toisen säikeen B toiminnasta -> A joutuu odottamaan, kunnes B saa suoritettua operaationsa Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 13 *x++=*y++ IX.4. Rinnakkaisuuden kontrollirakenteet Synkronoinnin hallinnan perusmekanismit Semaforit, Monitorit, Viestinvälittäminen Viestinvälittäminen (message passing) Välttämätön, jollei yhteistä muistialuetta Adan perusmekanismi Jaksottaminen hoidetaan lähettämällä ja vastaanottamalla viestejä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 14 *x++=*y++ IX.4.1. Semaforit Vanhimpia rinnakkaisen ohjelmoinnin rakenteita 1968 Dijkstra: THE –käyttöjärjestelmä E.W. Dijkstra, “The structure of ’THE’ multiprogramming system”, Communications of ACM, 11 (5), 1968, 341 - 346. Semafori-nimitys rautateiden opastimista Semafori: Kokonaislukumuuttuja, joka pitää yllä lupien lukumäärää, arvo ≥ 0 Lupien lukumäärä kuvaa yleensä yhtä aikaa toimivia säikeitä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 15 *x++=*y++ IX.4.1. Semaforit (2) Säie pääsee toimimaan jos saa luvan semaforilta, muuten odottaa Kun säie lopettaa toimintansa on ilmoitettava semaforille Operaatiot ( S on semafori) WAIT(S) (tai P(S)) SIGNAL(S) (tai V(S)) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 16 *x++=*y++ IX.4.1. Semaforit (3) Voidaan käyttää esim. Poissulkevuuden toteuttamiseen Laskurina Periaatteessa kaikki rinnakkaisuuden rakenteet voitaisiin toteuttaa pelkästään semaforeilla Monissa tapauksissa kömpelöä Monissa käyttöjärjestelmissä semafori on ainoa rinnakkaisuuden kontrollirakenne UNIX ja Windows tukevat suoraan semaforeja Melko harvinaisia ohjelmointikielissä Algol68 ja PL/I Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 17 *x++=*y++ IX.4.2. Monitorit Semaforit eivät sovi hyvin rakenteiseen ohjelmointiin -> Tarvittiin uusi rakenne, joka käyttäisi datan kapselointia C.A.R. Hoare 1974 Esitteli monitorin käsitteen “Monitors: an operating system structuring concept”, Communications of ACM, 17 (10) 549- 557, 1974 Concurrent Pascal (Brinch Hansen 1975) Ensimmäinen ohjelmointikieli, jossa monitorit käytössä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 18 *x++=*y++ IX.4.2. Monitorit (2) Kapseloivat halutut toiminnot sisäänsä Suoritus mahdollinen vain monitorin suostumuksella Vain yksi säie kerrallaan: säikeellä hallussaan monitorin lukko (lock) Monitorin odotusjoukko (wait set) Sisältää suoritusta odottavat säikeet Voi jakaantua osajoukkoihin ehtomuuttujien (condition variables) suhteen Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 19 *x++=*y++ IX.4.2. Monitorit (3) Ilmoittaminen (notify, signal) Lukkoa hallussaan pitävän säikeen luopuminen lukosta Odotusjoukosta valitaan jokin säie toimimaan Mahdollista osoittaa, että monitori voidaan toteuttaa semaforeilla ja päinvastoin -> monitori ja semafori ilmaisuvoimaltaan yhtä vahvoja Monitori kuitenkin käytettävyydeltään korkeammalla tasolla Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 20 *x++=*y++ IX.5. Rinnakkaisuus Javassa IX.5.1. Javan säikeet Käyttäjäsäikeet (user threads) varsinaiset säikeet Demonisäikeet (daemon threads) toimivat taustalla Ohjelma loppuu, kun sen kaikki käyttäjäsäikeet päättyvät tai kutsutaan Runtime-luokan exit-metodia (koodissa System.exit(0);) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 21 *x++=*y++ IX.5.2.Säikeen luominen Javassa Kirjoita luokka, joka perii Thread-luokan run-metodi ylikirjoitettava TAI Kirjoita luokka joka toteuttaa Runnable-rajapinnan toteutettava run-metodi Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 22 *x++=*y++ IX.5.2.Säikeen luominen Javassa Thread-luokan oliot kontrolloivat säikeitä: 1. Luo uusi Thread-olio 2. Konfiguroi • Anna prioriteetti ja nimi (ei pakollinen) 3. Käynnistä kutsumalla start-metodia HUOM1: Käynnistys kutsumalla startia, toiminnallisuus runissa! HUOM2: Säie päättyy, kun run loppuu. Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 23 *x++=*y++ IX.5.3. Synkronointi Javassa Javassa monitori sisäänrakennettu rinnakkaisuuden hallintamekanismi Jokainen olio voi toimia monitorina -> jokaisella oliolla on lukko ja odotusjoukko Javan monitorit ”Ilmoita ja jatka”-tyyppiä Ilmoituksen saanut säie odottaa, kunnes ilmoittaja poistuu monitorista ja alkaa tämän jälkeen suorittaa toimintojaan Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 24 *x++=*y++ IX.5.3.1. Esimerkki Javan synkronoinnista: syklinen puskuri Käytetään, kun yksi säie tuottaa toiselle säikeelle dataa ja data on saatava talteen, kunnes se on luettu. Voidaan toteuttaa taulukkona Kirjoitus ja lukeminen nopeaa ja yksinkertaista Pidettävä huoli siitä, että täyteen puskuriin ei enää kirjoiteta eikä tyhjästä lueta Viimeisen paikan jälkeen kirjoitetaan aina ensimmäiseen Luokkaan kirjoitetaan metodit put ja take, joilla kirjoitetaan puskuriin ja luetaan siitä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 25 *x++=*y++ IX.5.3.1.1. Kilpailun synkronointi syklisessä puskurissa Jos metodeja put ja take kutsutaan kahdesta säikeestä yhtä aikaa, voi tulla konflikti -> kilpailun synkronoinnilla estettävä Onnistuu kirjoittamalla metodit syknronoiduiksi = lisätään sen esittelyyn sana synchronized -> olio itse toimii monitorina Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 26 *x++=*y++ IX.5.3.1.1. Kilpailun synkronointi syklisessä puskurissa (2) Säie kutsuu synkronoitua metodia -> ottaa haltuunsa olion lukon Olion kaikkien synkronoitujen metodien suorittaminen estyy kunnes säie luopuu lukosta Lukosta luopuminen: 1.Synkronoitu metodi loppuu tai 2.Säie siirtyy odotustilaan Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 27 *x++=*y++ IX.5.3.1.2. Yhteistoiminnan synkronointi syklisessä puskurissa Yo. toteutuksen jälkeen koodissa vielä ongelma: tyhjästä puskurista luetaan ja täyteen kirjoitetaan. Oikea toiminta: Lukeva säie pysähtyy, ellei mitään luettavaa ole. Jatkaa toimintaansa vasta sitten, kun jokin kirjoittajasäie käy kirjoittamassa alkion taulukkoon. Kirjoittava säie pysähtyy, jos puskuri täynnä. Saa jatkaa toimintaansa vasta, kun jokin lukijasäie käy lukemassa alkion Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 28 *x++=*y++ IX.5.3.1.2. Yhteistoiminnan synkronointi syklisessä puskurissa (2) Käytetään wait/notify-metodeja wait, notify ja notifyAll ovat Object-luokan metodeja Koska kaikki oliot perivät Object-luokan, kaikilla olioilla on myös nämä metodit wait luopuu lukosta ja jää odottamaan ilmoitusta notify ja notifyAll annettuna toisesta säikeestä vapauttavat odottavia säikeitä Yhdistetään sekä kilpailun että yhteistoiminnan synkronointi -> Ratkaisu sykliselle puskurille Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 29 *x++=*y++ IX.5.3.1.3. Luokan koodi public class CircularBuffer{ protected final Object[] buffer; int putPtr = 0;int takePtr = 0; int queuedItems = 0; public CircularBuffer(int size){ buffer = new Object[size]; } // Put objects to buffer public synchronized void put(Object obj) throws InterruptedException{ // Take objects from buffer public synchronized Object take() throws InterruptedException{ while(queuedItems == 0) wait(); Object retObj = buffer[takePtr]; while(queuedItems ==buffer.length) wait(); takePtr = (takePtr+1) %buffer.length; queuedItems--; buffer[putPtr] = obj; putPtr = (putPtr+1)%buffer.length; queuedItems++; if(queuedItems == (buffer.length-1)) notifyAll(); if(queuedItems == 1) notifyAll(); } // End put() return retObj; } // End take() } // End class CircularBuffer Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 30 *x++=*y++ IX.6. Rinnakkaisuus C++-kielessä IX.6.1 Säikeet Standardiin C++11 lisätty rinnakkaisuuden tuki Säikeiden hallintaan luokka std::thread Voi suorittaa minkä tahansa funktion koodia omassa säikeessään Toinen säie voi odottaa päättymistä (metodi join) Ohjelma päättyy, kun pääohjelman säie loppuu -> voidaan tarvita join-kutsua Voidaan irrottaa taustasäikeeksi (metodi detach) Ei voida odottaa loppumista Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 31 *x++=*y++ IX.6.1 Säikeet. Esimerkki #include <iostream> #include <thread> void terve(){ std::cout << "Terve. Olen saie " << std::this_thread::get_id() << std::endl; } int main(){ std::thread saie(terve); saie.join(); std::cout << "Ohjelman loppu!" << std::endl; return 0; } Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 32 *x++=*y++ IX.6.2 Kilpailun synkronointi C++-kielessä Koodin lukitseminen muilta säikeiltä: Kutsutaan luokan std::mutex olion lock-metodia Ei voida suorittaa muista säikeistä ennen unlockkutsua Esimerkki: std::mutex lukko; void kasvata(){ lukko.lock(); ++arvo; lukko.unlock(); } Lukua arvo voi kasvattaa vain yhdestä säikeestä kerrallaan Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 33 *x++=*y++ IX.6.3 Yhteistoiminnan synkronointi C++-kielessä C++:ssa ei monitoria vastaavaa luokkaa Odottaminen ja ilmoittaminen ehtomuuttujilla: luokka std::condition_variable Esimerkki std::mutex lukko; std::condition_variable conOne; std::condition_variable conTwo; void kasvata(){ std::unique_lock<std::mutex> lck(lukko); while(arvo >= max) conOne.wait(lck); ++arvo; conTwo.notify_one(); } Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 34 *x++=*y++ IX.7. Rinnakkaisuus muissa ohjelmointikielissä PL/I IBM, 1960 – luvun puoliväli Ensimmäinen rinnakkaista ohjelmointia tukeva kieli Rinnakkaisuuden toteutus oli puutteellinen Simula (1966 – 67) Ensimmäinen oliokieli (joidenkin lähteiden mukaan ensimmäinen rinnakkainen kieli) Tuki myös rinnakkaisuutta (alkeelliseesti vuorottelualiohjelmien [coroutines] avulla) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 35 *x++=*y++ IX.7. Rinnakkaisuus muissa ohjelmointikielissä (2) Pascal Ei tue rinnakkaisuutta 1970 –luvun puolivälissä Concurrent Pascal Sisälsi ensimmäisenä monitorin C Ei tue rinnakkaisuutta Kehitetty Concurrent C Voidaan toteuttaa rinnakkaisuus käyttöjärjestelmän ominaisuuksien avulla Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 36 *x++=*y++ IX.7. Rinnakkaisuus muissa ohjelmointikielissä (3) Ada 1983 Yhdysvaltain puolustusministeriön kehitysprojekti Tukee rinnakkaista ohjelmointia (Adan säie = task) Synkronointi perustuu viestinvälitykseen 1995 parannettu versio C# Rinnakkaisuus samankaltainen kuin Javassa Muutokset Sebestan mukaan merkittäviä ja parantavat Javan säietoteutusta Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Rinnakkainen ohjelmointi 37