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