10 Lock Avainsanan lock (Lock keyword) avulla voidaan toteuttaa prosessien ja säikeiden välisessä keskinäisessä kommunikoinnissa käytettäviä synkronointi- ja poissuljentarakenteita. Tämän niin sanotun Lock-lauseen avulla voidaan kontrolloida säikeiden pääsyä suorittamaan kriittisen alueen ohjelmakoodia. Lock-lauseen (lockstatement) avulla voidaan toteuttaa näitä kriittisiä ohjelmalohkoja, joissa olevaa ohjelmakoodia pääsee suorittamaan vain yksi säie kerrallaan. Nämä ohjelmalohkot suoritetaan siten, että toiset säikeet eivät pääse keskeyttämään suoritusta ennen, kuin koko lohko on kokonaan suoritettu loppuun kyseisen säikeen toimesta. Kuva 10-1 havainnollistaa lock-lauseen käyttöä. Kuva 10-1. Lock-lauseen käyttö. 10.1 Lock-lause Lock-lause voidaan toteuttaa lock-avainsanan avulla. Lock-lauseen avulla voidaan toteuttaa synkronointi-/poissuljentarakenne eli tässä tapauksessa ohjelmalohko, jossa olevaa ohjelmakoodia pääsee suorittamaan vain yksi säie kerrallaan. Lock-lauseen toteuttamisessa tarvitaan lukitusobjektia. Lukitusobjekti on mikä tahansa objekti, joka on kyseisen lock-lauseen näkyvyysalueella. Tavallisesti lukitusobjekti on kuitenkin kyseistä lock-lausetta varten luotu Object-tyyppinen olio. Lock-lause toimii siten, että jos jokin säie on suorittamassa Lock-lauseella suojattua ohjelmalohkoa ja samaan aikaan toinen säie yrittää päästä suorittamaan samalla lukitusobjektilla suojattua samaa tai eri ohjelmalohkoa, niin se pysäytetään, siksi aikaa kunnes kyseinen lukitusobjekti vapautuu eli ensimmäinen kyseistä ohjelmalohkoa suorittamassa oleva säie lopettaa Lock-lauseella suojatun lohkon suorittamisen ja vapauttaa lukitusobjektin ja näin koko lohkon. Lukitusobjektin näkyvyysalue määrää sen, missä rakenteissa sitä voidaan käyttää. Lock-lauseen saa toteutettua siten, että ensin luodaan lukitusobjekti ja sitten käytetään tätä objektia lock-lohkon lukituksessa. www.stickmansoft.com 273
Object lockobject = new Object(); lock (lockobject) // Only one thread at a time may execute this statement. 10.1.1 OsLock-ohjelma OsLock-ohjelma on esimerkki sitä, kuinka lock-avainsanaa käytetään Lock-lauseen toteuttamisessa. Ohjelmassa luodaan kaksi säiettä ohjelman käynnistyksen yhteydessä. Molemmat säikeet liikuttavat omaa ufoa näytöllä. Lock-lauseen avulla säikeiden ufon liikutuksen hoitava osa ohjelmakoodista on sijoitettu Lock-lauseella suojattuun lohkoon. Tällöin vain toinen säie voi liikuttaa omaa ufoaan ja toinen säie joutuu odottamaan vuoro eli Lock-lohkon vapautumista toiselta säikeeltä. Tämä Lock-lauseella suojattu lohko simuloi tässä ohjelmassa kriittistä aluetta eli aluetta, jota saa suorittaa vain yksi säie kerrallaan. Ohjelma koostuu Program.cs-tiedostosta, formista ja siihen liitetystä OsForm.cs-lähdetekstitiedostosta sekä erillisestä Ufo.cs-luokkatiedostosta. Seuraavassa on esitelty edellä mainittujen lähdetekstitiedostojen sisältämät ohjelmakoodit. Program.cs Program.cs-lähdetekstitiedosto sisältää Main()-metodin eli ohjelman aloituskohdan. Kuvassa 10-2 on esitetty Program.cs-tiedoston ohjelmakoodi. /* Program.cs Copyright Markku Rahikainen. www.stickmansoft.com */ using System; using System.Collections.Generic; using System.Windows.Forms; namespace OsFrame static class Program static void Main() Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new OsForm()); Kuva 10-2. OsLock-ohjelman Program.cs-tiedosto. 274 C# Systeemiohjelmointi
OsForm.cs OsForm.cs-lähdetekstitiedosto on ohjelman formiin liitetty lähdetekstitiedosto. Kuvassa 10-3 on esitetty OsForm.cs-tiedoston ohjelmakoodi. /* OsForm.cs Copyright Markku Rahikainen. www.stickmansoft.com */ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace OsFrame public partial class OsForm : Form private Object lockobject = new Object(); private Thread ufothread1 = null; private Thread ufothread2 = null; private Boolean ufothreadrunning = false; public OsForm() InitializeComponent(); // Create a thread 1. ufothread1 = new Thread(new ParameterizedThreadStart(UfoProcedure)); ufothread1.start("ufo1"); // Create a thread 2. ufothread2 = new Thread(new ParameterizedThreadStart(UfoProcedure)); ufothread2.start("ufo2"); private void OsMenuFileExit_Click(object sender, EventArgs e) ApplicationExit(); private void OsForm_FormClosing(object sender, FormClosingEventArgs e) ApplicationExit(); www.stickmansoft.com 275
private void ApplicationExit() ufothreadrunning = false; Application.Exit(); private void UfoProcedure(object Data) Ufo ufo = new Ufo(Convert.ToString(Data)); ufothreadrunning = true; Random Rand = new Random(DateTime.Now.Millisecond); while (ufothreadrunning) // Blocks the thread until // block is released. lock (lockobject) int i = 100; while (i > 0 && ufothreadrunning) i--; ufo.movetheufo(clientsize, OsMenu.Height); ufo.drawtheufo(creategraphics()); Thread.Sleep(Rand.Next(10, 50)); Thread.Sleep(0); Kuva 10-3. OsLock-ohjelman Program.cs-tiedosto. Ufo.cs Ufo.cs-lähdetekstitiedosto sisältää luokan ufon käsittelyyn. Luokassa on ohjelmarakenteet ufo-kuvan lataamista, ufon liikuttamista ja ufon näytölle tulostamista varten. Kuvassa 10-4 on esitetty Ufo.cs-tiedoston ohjelmakoodi. /* Ufo.cs Copyright Markku Rahikainen. www.stickmansoft.com */ using System; using System.Collections.Generic; using System.Text; 276 C# Systeemiohjelmointi
using System.Drawing; using System.Windows.Forms; namespace OsFrame class Ufo private Image ufo; private int xpos = 50; private int xspeed = 1; private int xdir = 1; private int ypos = 50; private int yspeed = 1; private int ydir = 1; public Ufo() public Ufo(string Ufo) try // Load background. background = new Bitmap("..\\..\\UfoBackground.gif"); // Load a ufo image. ufo = new Bitmap("..\\..\\" + Ufo + ".gif"); catch (Exception ex) MessageBox.Show("Error: " + ex.tostring(), "Ufo load failed"); ~Ufo() // Release ufo. ufo.dispose(); public void MoveTheUfo(Size ClientSize, int MenuHeight) // Update UFO y position. xpos += xspeed * xdir; if (xpos < 0 xpos > ClientSize.Width - ufo.width) xdir *= -1; // Update UFO x position. ypos += yspeed * ydir; www.stickmansoft.com 277
if (ypos < MenuHeight ypos > ClientSize.Height - ufo.height) ydir *= -1; public void DrawTheUfo(Graphics Graf) // Draw ufo to the screen. Graf.Clear(Color.White); Graf.DrawImage(ufo, xpos, ypos); Graf.Dispose(); Kuva 10-4. OsLock-ohjelman Ufo.cs-tiedosto. Kun OsLock-projektin toteuttaa, suorittaa ohjelman kääntämisen ja käynnistää ohjelman, niin näyttö on kuvan 10-5 mukainen. Kuva 10-5. OsLock-ohjelman tulostus. 278 C# Systeemiohjelmointi