1 / 20

Programske paradigme i jezici

SVEUČILIŠTE U ZAGREBU FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA Zavod za primijenjen o računarstvo. Programske paradigme i jezici. 8. auditorne vježbe (Multithreading). Višenitnost (višedretvenost, eng. multithreading).

arvin
Download Presentation

Programske paradigme i jezici

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. SVEUČILIŠTE U ZAGREBU FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA Zavod za primijenjenoračunarstvo Programske paradigme i jezici 8. auditorne vježbe (Multithreading)

  2. Višenitnost (višedretvenost, eng. multithreading) • Višenitni program sastoji se od 2 ili više dijelova koji se mogu istovremeno izvršavati (pseudo-paralelizam). Svaki dio takvog programa naziva se nit ili dretva (eng. thread). • Ime dolazi od ‘thread of execution’. Svaki proces ima barem jednu nit. • Primjer: tekst procesor, web server, matrični kalkulator... • Prednost: Bolja iskoristivost procesorskog vremena, posebno kod programa koji imaju sporiji I/O. Progress

  3. Višenitnost • Razredi koji podržavaju višenitno programiranje nalaze se u prostoru imena System.Threading • Kako bi se koristila nit, treba instancirati objekt tipa Thread. • Najčešće korišteni konstruktori razreda Thread public Thread(ThreadStart start) public Thread(ParameterizedThreadStart start) • start je ime postupka koja će biti pozvan kako bi počelo izvršavanje niti. • ThreadStart je delegat (neprecizno rečeno: pokazivač na postupak) • Jednom kreirana nit se pokreće postupkom Start() SimpleThread

  4. Višenitnost (SimpleThread program) using System; using System.Threading; class MojThread{ public int brojac; string imeThreada; public MojThread(string ime){ brojac=0; imeThreada = ime; } //entryPoint , tj. postupak s kojim će se startati thread, //može nositi bilo koje ime, ne može primiti nijedan parametar* public void run(){ Console.WriteLine(imeThreada + " startan"); do { Thread.Sleep(500); Console.WriteLine("\nUnutar " + imeThreada + ", brojac=" + brojac); brojac++; } while(brojac<5); Console.WriteLine(imeThreada + " završio"); } *ParameterizedThreadStart može imati 1 parametar

  5. Višenitnost (SimpleThread program) class Glavni { public static void Main() { Console.WriteLine("Glavni thread startan."); //instanciramo MojThread objekte MojThread mt1 = new MojThread("PPJ-#1"); MojThread mt2 = new MojThread("PPJ-#2"); //konstruiramo Thread objekte Thread thread1 = new Thread(new ThreadStart(mt1.run)); Thread thread2 = new Thread(new ThreadStart(mt2.run)); //startamo threadove thread1.Start();thread2.Start(); do { Console.Write("."); Thread.Sleep(100); } while (mt1.brojac<5 && mt2.brojac<5); Console.WriteLine("Kraj glavnog threada"); } }

  6. Višenitnost • Statička metoda Sleep uzrokoje privremeno zaustavljanje izvršavanja niti iz koje je pozvana za navedeni broj milisekundi. • Načinimo neke promjene u prethodnom programu • Neka se nit pokreće odmah pri instanciranju. Ovo ćemo napraviti instancirajući Thread unutar konstruktora razreda MojThread. • Svaki Thread objekt ima svojstvo Name što možemo koristiti umjesto imeThread. • Neka glavni program koristi neki drugi način utvrđivanja kraja pokrenutih niti pomoću metode IsAlive • public bool IsAlive {get; } SimpleThread2

  7. Višenitnost (SimpleThread2 program) using System; using System.Threading; class MojThread{ public int brojac; public Thread thread; public MojThread(string ime) { brojac=0; thread = new Thread(new ThreadStart(this.run)); thread.Name = ime; thread.Start(); } public void run(){ Console.WriteLine(thread.Name + " startan"); do { Thread.Sleep(500); Console.WriteLine("\nUnutar " + thread.Name + ", brojac=" + brojac); brojac++; } while(brojac<5); Console.WriteLine(thread.Name + " završio"); }

  8. Višenitnost (SimpleThread2 program) class Glavni { public static void Main() { Console.WriteLine("Glavni thread startan."); //instanciramo MojThread objekte MojThread mt1 = new MojThread("PPJ-#1"); MojThread mt2 = new MojThread("PPJ-#2"); do { Console.Write("."); Thread.Sleep(100); } while (mt1.thread.IsAlive && mt2.thread.IsAlive); Console.WriteLine("Kraj glavnog threada"); } } } • Drugi način čekanja na završetak pojedine niti je Join postupak. Najjednostavniji oblik je public void Join() • Join čeka dok se nit na kojoj je pozvan ne završi. U slučaju da nit nije pokrenuta dogodit će se iznimka: ThreadStateException mt1.thread.Join(); mt2.thread.Join(); Join uzrokuje blokiranje niti dok nit na koju se čeka ne završi.

  9. Višenitnost (prioriteti) • Postavljanje prioriteta pojedine niti obavlja se preko svojstva Priority koji je član razreda Thread. Njegov opći oblik je public ThreadPriority Priority{ get; set; } • ThreadPriorityje pobrojani tip koji definira sljedeće prioritete: • ThreadPriority.Highest • ThreadPriority.AboveNormal • ThreadPriority.Normal (inicijalna vrijednost) • ThreadPriority.BelowNormal • ThreadPriority.Lowest • Sljedeći primjer kreira dvije niti, jednu višeg prioriteta, a drugu nižeg koje završavaju onog trenutka kada brojač u jednoj od njih dođe do 1 000 000 000. PriorityDemo

  10. Višenitnost (PriorityDemo) using System; using System.Threading; class MojThread{ public int brojac; public Thread thread; static bool stop=false; static string trenutnoIme; public MojThread(string ime){ brojac=0; thread = new Thread(new ThreadStart(this.run)); thread.Name = ime; trenutnoIme = ime; } public void run(){ Console.WriteLine(thread.Name + " startan"); do{ brojac++; if (trenutnoIme!=thread.Name){ trenutnoIme = thread.Name; Console.WriteLine(" Aktivan: " + trenutnoIme); } }while(stop==false && brojac<1000000000); stop = true; Console.WriteLine(thread.Name + " završio"); } }

  11. Višenitnost (PriorityDemo) class PriorityDemo { public static void Main() { Console.WriteLine("Glavni thread startan."); //instanciramo MojThread objekte MojThread mt1 = new MojThread("Viseg Prioriteta"); MojThread mt2 = new MojThread("Nizeg Prioriteta"); //postavimo prioritete mt1.thread.Priority = ThreadPriority.AboveNormal; mt2.thread.Priority = ThreadPriority.BelowNormal; //pokrenimo threadove mt1.thread.Start(); mt2.thread.Start(); mt1.thread.Join(); mt2.thread.Join(); Console.WriteLine("Brojac u " + mt1.thread.Name + "je dosao do" + mt1.brojac); Console.WriteLine("Brojac u " + mt2.thread.Name + "je dosao do" + mt2.brojac); } }

  12. Višenitnost (stanja niti) • Stanje niti može se dobiti iz svojstva ThreadState koji se nalazi unutar razreda Thread: public ThreadState ThreadState {get; } • Stanje može poprimiti jednu od sljedećih vrijednosti: ThreadState.Aborted ThreadState.AbortRequested ThreadState.Background ThreadState.Running ThreadState.Stopped ThreadState.StopRequested ThreadState.Suspended ThreadState.SuspendRequested ThreadState.Unstarted ThreadState.WaitSleepJoin • Referencu na trenutno nit možemo dobiti pomoću svojstva CurrentThread

  13. Višenitnost (Suspend, Resume, Abort) • Thread.Suspend() – privremeno zaustavlja izvršavanje niti • Thread.Resume() – ponovo pokreće privremeno zaustavljenu nit • Thread.Abort() – uzrokuje ThreadAbortException na niti na kojoj se izvrši, što uzrokuje završetak niti • Napomena: Ova iznimka može biti uhvaćena, ali se automatski ponovo generira, osim u slučaju ako se pozove metoda ResetAbort() • SuspendResumeAbort

  14. Višenitnost (Suspend, Resume, Abort) using System; using System.Threading; class MojThread{ public Thread thread; public MojThread(string ime){ thread = new Thread(new ThreadStart(this.run)); thread.Name = ime; thread.Start(); } public void run(){ Console.WriteLine(thread.Name + " startan"); for (int i=1; i<=200 ; i++){ Console.Write(i + " "); if ((i%10)==0){ Console.WriteLine(); Thread.Sleep(250); } } Console.WriteLine(thread.Name + " završio"); }

  15. Višenitnost (Suspend, Resume, Abort) class SuspendResumeAbort{ public static void Main(){ MojThread mt1 = new MojThread("Moj Thread"); Thread.Sleep(1000); mt1.thread.Suspend(); Console.WriteLine("Suspending Thread"); Thread.Sleep(1000); mt1.thread.Resume(); Console.WriteLine("Resuming Thread"); Thread.Sleep(1000); mt1.thread.Suspend(); Console.WriteLine("Suspending Thread"); Thread.Sleep(1000); mt1.thread.Resume(); Console.WriteLine("Resuming Thread"); Thread.Sleep(1000); Console.WriteLine("Stopping Thread"); mt1.thread.Abort(); mt1.thread.Join(); Console.WriteLine("Kraj glavnog threada"); } } Uočimo da nit nije ispisala poruku da se normalno završila (dogodila se neuhvaćena iznimka) Kao parametar za Abort možemo unijeti bilo koji objekt.Unesimo npr. neki broj mt1.thread.Abort(100);

  16. Višenitnost (Suspend, Resume, Abort) public void run(){ Console.WriteLine(thread.Name + " startan"); for (int i=1; i<=200 ; i++){ Console.Write(i + " "); if ((i%10)==0){ Console.WriteLine(); Thread.Sleep(250); } } Console.WriteLine(thread.Name + " završio"); } try{ Uhvatimo ThreadAbortException i ispišemo odgovarajuću poruku } catch(ThreadAbortException exc) { Console.WriteLine("Thread aborted, code: " + exc.ExceptionState); } Thread.ResetAbort(); Console.WriteLine("Resetiram abort->nastavljam izvršavanje"); Uočimo poruku

  17. Višenitnost (Sinkronizacija) • Promotrimo sljedeći primjer: Neka su startane 3 niti, i neka svaka od njih treba u zajedničku datoteku zapisati nekoliko rečenica, ali pišući znak po znak. Svaka od niti u svom konstruktoru kao parametar će dobiti listu rečenica (ArrayList- varijabla recenice) koje treba zapisati u datoteku i StreamWriter (varijable writer) pomoću kojeg će vršiti upisivanje u datoteku. Kod koji upisuje u datoteku neka je sljedeći: foreach(String s in recenice){ foreach (char c in s){ Thread.Sleep(10); writer.Write(c); } writer.WriteLine(); } • WriteSentence_NoSync • Pokrenemo li gornji program vidjet ćemo da nam je ispis u datoteci izmiješan. • Zaštitit ćemo pristup pojedinom dijelu koda, kako bi omogućili da rečenice budu pravilno ispisane. • WriteSentence • AccountTransaction lock(writer){ Programski odsječak u kojem se pojedina rečenica zapisuje ogradimo sa lock(writer) i onemogućimo istovremeni ulazak dviju niti u taj odsječak. }

  18. Višenitnost (Sinkronizacija) • Opći oblik lock naredbe je lock(object){ //programski odsječak koji treba sinkronizirati } • lock naredba osigurava da dio programa zaštićen lock-om (lock nad nekim objektom) može biti izvršavan samo onom niti koja je vlasnik tog lock-a. • Ako neka nit ‘zaključa’ object sve ostale niti koje pokušaju ući u neki programski odsječak koji je zaštićen tim istim objektom moraju čekati dok nit ‘vlasnik’ objekta ne napusti zaštićeni odsječak. • lock objekt može biti bilo što (pa i string), ali treba paziti da ne dođe do potpunog zastoja. Najbolje je koristiti privatni objekt namijenjen isključivo za tu svrhu. • lock je zapravo jednostavni oblik korištenja sinkronizacijskih postupaka definiranih u razredu Monitor. Definirano je nekoliko postupaka: Enter,Exit,TryEnter,Wait,Pulse,PulseAll

  19. Višenitnost (Sinkronizacija) • Promotrimo sljedeću situaciju: Neka je nit A pozvala postupak T koji je ušao unutar zaštićenog bloka (ili sa lock ili sa Monitor.Enter) i u nekom trenutku treba pristup resursu R koji privremeno nije dostupan. Što A treba napraviti? Ako A u nekoj petlji bude čekao na resurs R i dalje će držati vlasništvo nad objektom T, sprečavajući neke druge niti da uđu u odsječke zaštićene tim objektom. Rješenje je da A privremeno otpusti vlasništvo nad objektom i omogući nekoj drugoj niti ulazak u kritični odsječak. Kada resurs R postane dostupan, nit A će biti obaviještena i moći će nastaviti svoje izvršavanje uz ponovo zaključavanje objekta. Gornje rješenje omogućuju postupci Wait (čekanje određenog objekta) te Pulse (notificiranje o dostupnosti objekta) • TickTock • Opasnost od potpunog zastoja!

  20. Višenitnost (Sinkronizacija) • Semafori ograničavaju broj niti koje mogu istovremeno pristupiti određenom resursu (kritičnom odsječku) • Ukoliko je trenutna vrijednost semafora nula, niti čekaju dok se vrijednost ne poveća. Ovisno o vrijednosti semafora toliki broj niti dobiva pravo izvršavanja kritičnog odsječka. Redoslijed odabranih nije deterministički. • Najčešći konstruktor: Semaphore(int initialCount, int maximumCount) • Najčešći postupci WaitOne() Release() • Progress

More Related