MikroBitti
<A HREF="http://adserver.sanomawsoy.fi/adclick/CID=000035214e1929b700000000/SITE=02_MBNET/AREA=ETUSIVU.IT.VAPAAAIKA/AAMSZ=120x60/PP=1/relocate=http://track.adform.net/C/?bn=33304;ADFrnd=525386990;C=0" TARGET="_blank"><IMG SRC="http://track.adform.net/Banners/40699.gif" WIDTH="120" HEIGHT="90" ALT="" BORDER="0"></a> <A HREF="http://track.adform.net/C/?bn=33705;ADFrnd=520885647;C=0" TARGET="_blank"><IMG SRC="http://track.adform.net/Banners/42145.gif" WIDTH="728" HEIGHT="90" ALT="" BORDER="0"></a>

Sisällysluetteloon
MikroBitti
SUOMEN SUURIN UUDEN TEKNIIKAN LEHTI
  Katapultti  

MikroBitin palvelut
Säikeillä säpinää makkarakoodiin takaisintakaisin


Säikeet ovat miniohjelmia, joita voidaan suorittaa useita kappaleita rinnakkain. Näin ohjelmoidaan sovelluksia, jotka osaavat tehdä asioita taustalla tai vaikkapa palvella useita nettikäyttäjiä samanaikaisesti. Säikeet eivät ole vaikeita, kunhan ymmärtää pari rinnakkaisuuteen liittyvää perusongelmaa ja niiden ratkaisut. MikroBitissä 11/2002 käsittelimme säikeitä sivuilla 80-83.


Filosofit kiinalaisessa ravintolassa

Lehtijutussa havainnollistimme säikeistykseen liittyvää tahdistusta, lukkiutumista, nälkiintymistä ynnä muita ilmiöitä esimerkillä, jossa filosofit ruokailevat kiinalaisessa ravintolassa. Rakensimme Java-kielellä ohjelman, jolla voit itse tutkia säikeistyksen ongelmia ja ratkaisuja.

Kopioi Java-kielinen lähdekoodi kotiin:
Kopioi Java-lähdekoodi kotiin
Filosofi.zip (187 kt)


Filosofit kiinalaisessa ravintolassa
Filosofit kiinalaisessa ravintolassa
  Filosofi

 

Säikeet ja Java2

Java-kielellä säiekoodaus on suhteellisen selkeää, kunhan asiaan malttaa perehtyä.

Säie - omaa sukua Thread

Javassa on kaksi tapaa kirjoittaa säieominaisuuksilla varustettu luokka. Suoraviivaisinta on periyttää uusi luokka kantaluokasta Thread, ja ylittää sen run-metodi perillisessä. Toinen konsti on laajentaa jo olemassa olevaa luokkaa Runnable-liittymällä, jonka myötä säieominaisuudet siirtyvät mihin tahansa luokkaan.

Säieolio käynnistetään metodilla start, joka suorittaa run-metodin. Run:ia ei koskaan kutsuta suoraan. Syy tähän on yksinkertainen: vain käyttöjärjestelmä voi luoda säikeitä. Start on tilaus, jonka vastineeksi käyttöjärjestelmä toimittaa uuden säikeen tilaajalle. Run-metodin kutsuminen suoraan toteuttaa säieluokkaan kirjoitetun koodin, mutta käyttäen samaa säiettä kuin kutsuja - eli normaaliin peräkkäiseen tyyliin rinnakkaisen sijaan.

Kun säie on suorittanut run-metodiinsa kirjoitetut käskyt, sen elämä päättyy. Säieolion starttia voi kutsua vain kerran olion elinaikana. Uutta käynnistystä varten oliosta on luotava uusi ilmentymä. Oheisessa taulukossa on malli säieolion luomisesta:

Java2-komento Selitys
Philosopher Descartes; Määritellään Thread-luokasta periytetyn Philosopher-luokan edustaja Descartes
Descartes = new Philosopher(this); Luodaan Descartes-olioksi Philosopher-ilmentymä. Philosopher-luokassa on määritetty kuuntelijaolio, joka välitetään luokan konstruktorille. Tässä kuuntelijaksi esitetään säikeen luovaa oliota itseään (this).
Descartes.setName("Descartes"); Annetaan oliolle nimi - Thread-luokassa on valmiina metodi setName()
Descartes.setDaemon(true); Descartes-oliosta tehdään demoni. Se ei elä luojaansa kauemmin.
Descartes.setPriority(4); Descartesin kiireellisyysasteeksi laitetaan arvo 4. Prioriteetti on lukuarvo väliltä 1 -10. Mitä suurempi luku sitä enemmän säikeelle myönnetään suoritusaikaa.
Descartes.start(); Käynnistetään Descartes, jonka jälkeen se toimii omia aikojaan käynnistäneen luojasäikeen rinnalla.


Synchronized

Olio lukitaan Javassa komennolla synchronized(olio). Myös pelkän metodin voi synkronoida tyyliin: public synchronized void teeJotain()

Ero lukitustapojen välillä on puhtaasti semanttinen. Synkronointi lukitsee aina koko olion - eli jos olio A kutsuu olion B synkronoitua metodia, räpsähtää koko B-olio säppiin. Lukituksen aikana vain A pääsee käsiksi B:n metodeihin.

Lukitsija voi kohdistaa lukittavaan useita peräkkäisiä synkronointikäskyjä. Lukko puree vain kilpaileviin säikeisiin - eli "itseensä lukkiutumista" ei tarvitse pelätä.

Mikäli jokin muu olio, esimerkiksi C, on ehtinyt lukita B:n ensin, joutuu A odottamaan, kunnes C vapauttaa lukon. Lukko kirpoaa, kun lukitsijan suoritus ennättää synchronized-komennon jälkeiseen sulkevaan aaltosulkuun:

/* Olio A */
Synchronized(B)
{ /* B on lukittu, muut säikeet eivät pääse kiinni B:hen ennen
     kuin lukko on taas auki */
   B.teeSita();  
   B.teeTata();
} /* tämä aaltosulku vapauttaa lukon */

Yield

Joissain käyttöjärjestelmissä säikeet onnistuvat rohmuamaan koko prosessoriajan kerran käynnistyttyään. Mikäli säikeen run-metodissa on hellittämättömiä ikisilmukoita, kannattaa iteroinnin keskelle istuttaa yield-komento. Se antaa muillekin säikeille hetkeksi mahdollisuuden päästä mukaan suoritukseen. Yield ei pysäytä komennon esittävää säiettä, toisin kuin sleep-käsky. Käytä yield:iä, niin ohjelmasi toimii kiltisti kaikissa käyttöjärjestelmissä.

Sleep

Säikeen laittaminen nokosille vapauttaa prosessoriaikaa muille säikeille. Unikomennossa määritetään millisekunteina aika, jonka säie viettää höyhensaarilla. Sleep(1000) pistää säikeen sekunniksi ettosille.

Wait ja notify

Säieorkesterin johtamiseen sovelias apuri on komento wait, joka pysäyttää säikeen määräämättömäksi ajaksi, kunnes säie kannustetaan jatkamaan suoritustaan notify-komennolla. NotifyAll hätistelee kaikki pysäytetyt säikeet liikkeelle.

Interrupt

Joskus säie on tarpeen panna päiviltä kertaheitolla. Komento interrupt nostaa säikeessä lipun, johon reagointi on jätetty ohjelmankirjoittajan vastuulle. Samoin kuin aiemmin suosittelimme yield-komennon sijoittelua säielogiikan tiukkoihin silmukoihin, on sitäkin tärkeämpää tarkkailla keskeytyslipun tilaa. Jos ruutulippu liehuu, lopetellaan run-metodi hallitusti. Interrupt aiheuttaa nukkuvassa säikeessä virheen heittävän keskeytyksen, ja siksi sleep-komento onkin ympäröitävä try-catch-rakenteella.


Malliohjelma Philosophers.java

Niille, joita kiinnostaa teorian soveltaminen käytännössä, olemme laatineet java2-kielisen malliohjelman.

Kopioi Java-kielinen lähdekoodi kotiin:
Kopioi Java-lähdekoodi kotiin
Filosofi.zip (187 kt)

Sovelluksen kokoonpano:

Java-luokka Toiminta
Philosophers.java Käyttöliittymäikkuna. Operatiivinen keskus, joka piirtää sovellusikkunan ja kanavoi käyttäjän toimenpiteet jäsenolioilleen.
ButtonPanel.java Painikevalikko. Ikkunan vasemman laidan painikkeet. "Aloita" ja Lopeta". Painikkeilla käynnistetään ja pysäytetään viiden filosofisäikeen illanvietto ravintolassa.
RestaurantPanel.java Ravintolapaneeli. Käyttöliittymässä näkyvä pelkistetty ravintolasali pyöreän pöydän ympärillä istuvine filosofeineen vastaa säikeiden monitoroinnista. Tämä luokka myös perustaa ja tappaa säikeet. Lisäksi se välittää sekä painikevalikon että säätöpaneelin käskyt säikeille.
SettingPanel.java Pääikkunan alareunan liukuvalitsimet ruokahalulle, nälkiintymiselle ja ruokailun kestoajalle.
Philosopher.java Säieluokka. Jokainen viidestä filosofista on tämän luokan ilmentymä.
PopupPri.java Ponnahdusvalikko filosofisäikeiden priorisointiin.
PhListener.java Säietapahtumien kuuntelijaliittymä, jonka RestaurantPanel toteuttaa.
PopListener.java Ponnahdusvalikon kuuntelijaliittymä, jonka RestaurantPanel toteuttaa.
SbarListener.java Liukuvalintojen kuuntelijaliittymä, jonka käyttöliittymä (Philosophers) toteuttaa.
WinExit.java Pääsäikeen suorituksen ikkunan sulkemisen yhteydessä päättävä luokka.
CommonFunctions.java Yleiskäyttöisiä funktioita, kuten merkkijonon kokonaislukukonversio yms.
Constants.java Globaalit vakiomuuttujat, joita eri luokat tarvitsevat.

Säikeiden kannalta kiinnostavimmat ohjelman osat ovat RestaurantPanel.java ja Philosopher.java. Muut luokat keskittyvät käyttöliittymän yleiseen muodostamiseen.

Lähdekoodit ovat .java-loppuisia, käännetyt objektit puolestaan .class-päätteisiä. Lähdekoodit on kirjoitettu Modelworks:in JPadPro:lla, josta voi noutaa 30-päivän ilmaisen kokeiluversion osoitteesta http://www.modelworks.com/. Lähdekoodeja voi toki muokata muillakin välineillä, kuten WordPad:lla, MS Wordilla tai millä tahansa muulla teksturilla.

Ohjelman suorittamiseksi täytyy koneelta löytyä Sun:in Java2 JRE (Java Runtime Environment). Sen voi kopioida ilmaiseksi Sun Microsystemsin kotisivulta http://www.sun.com/. Asenna oheisen zip-tiedoston sisältö esimerkiksi kansioon nimeltä c:\filosofit.

Zipin purettuasi löydät java-luokkien ja kuvatiedostojen seasta philosophers.bat-komentojonon. Muuta komentojonon polkumääreet oman koneesi java-hakemistoa ja filosofi-kansiota vastaaviksi. Bat-tiedostossa on ohjeet kuinka toimia. Kun koneellasi on Javan-ajoympäristö, Philosophers-sovellus ja ajantasainen ajojono, voit käynnistää sovelluksen tuplaklikkaamalla Philosophers.bat-tiedoston kuvaketta.

Säikeiden tilat

Alkutilassa pöydän ympärillä näkyy viisi filosofia ja viisi syömäpuikkoa. Ajattelevat filosofit näyttävät tältä:

Kun filosofia alkaa nälättää, hän nappaa oikealta puoleltaan puikon, jonka seurauksena pöydältä häviää vapaana oleva puikko ja filosofin kuvaan lisätään puikkoa puristava koura:

Kun filosofi onnistuu nappaamaan toisenkin puikon, hän siirtyy syömistilaan, joka ilmaistaan avonaisella suulla:

Mikäli nälänsietokyky ei ole maksimiarvossaan (äärioikealla) voi filosofi nääntyä nälkään. Kyseisen tilan osoittaa filosofin muuttuminen pääkalloksi:

Kun kaikki filosofit onnistuvat nappaamaan vain yhden puikon, seurauksena on lukkiutuma, jota kuvataan syömäpuikon lävistämällä pääkallolla:



Tapio Lehtimäki







<A HREF="http://track.adform.net/C/?bn=33490;ADFrnd=434642971;C=0" TARGET="_blank"><IMG SRC="http://track.adform.net/Banners/41099.gif" WIDTH="140" HEIGHT="350" ALT="" BORDER="0"></a>

   © Sanoma Magazines Finland Oy, MikroBitti 1999-2006 - käyttöehdot
Lehden etusivullePalauteToimitusTilausTulossaInfoNettijatkotMBlabraTilaajanurkkaDigilehtiMBnetiin