Programowanie Współbieżne

Podobne dokumenty
Programowanie Współbieżne

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Współbieżność w środowisku Java

Programowanie równoległe i rozproszone. Monitory i zmienne warunku. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Aplikacje w Javie- wykład 11 Wątki-podstawy

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Programowanie w Sieci Internet. Python: Wątki. Kraków, 12 grudnia 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

1 Wątki 1. 2 Tworzenie wątków 1. 3 Synchronizacja 3. 4 Dodatki 3. 5 Algorytmy sortowania 4

Programowanie wielowątkowe. Jarosław Kuchta

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Język Java wątki (streszczenie)

Stworzenie klasy nie jest równoznaczne z wykorzystaniem wielowątkowości. Uzyskuje się ją dopiero poprzez inicjalizację wątku.

Złap współbieżnie latające muchy

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Metody Metody, parametry, zwracanie wartości

using System;... using System.Threading;

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Java. Programowanie Obiektowe Mateusz Cicheński

Systemy operacyjne. Zajęcia 11. Monitory

Kurs programowania. Wykład 8. Wojciech Macyna. 10 maj 2017

Kurs programowania. Wykład 8. Wojciech Macyna

Programowanie komputerów

Obliczenia równoległe i rozproszone w JAVIE. Michał Kozłowski 30 listopada 2003

Programowanie równoległe i rozproszone. W1. Wielowątkowość. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Języki i Techniki Programowania II. Wykład 7. Współbieżność 1

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Wątki w Javie. Piotr Tokarski

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Zaawansowane programowanie w C++ (PCP)

Programowanie obiektowe

Wielowątkowość mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

Rozdział 4 KLASY, OBIEKTY, METODY

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Wykład 5 Okna MDI i SDI, dziedziczenie

msgbox("akcja: Początek, argument: " + argument.tostring()); Thread.Sleep(1000); //opóźnienie msgbox("akcja: Koniec"); return DateTime.Now.

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Programowanie obiektowe

Podstawy współbieżności

Programowanie wielowątkowe. Tomasz Borzyszkowski

C# 6.0 : kompletny przewodnik dla praktyków / Mark Michaelis, Eric Lippert. Gliwice, cop Spis treści

Wykład 8: Obsługa Wyjątków

Instrukcja laboratoryjna cz.3

Mechanizmy pracy równoległej. Jarosław Kuchta

Język Java wątki (streszczenie)

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Wyjątki (exceptions)

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Języki i techniki programowania Ćwiczenia 2

Ćwiczenie 1. Kolejki IBM Message Queue (MQ)

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Programowanie obiektowe

Dawid Gierszewski Adam Hanasko

Programowanie współbieżne Zadanie 5 - Podstawowe problemy programowania współbieżnego

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Multimedia JAVA. Historia

Współbieżność w Javie

WSPÓŁBIEŻNOŚĆ. MATERIAŁY:

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Leszek Stasiak Zastosowanie technologii LINQ w

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Języki i metodyka programowania. Język C# pętle, sterowanie, wyjątki

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Podstawy i języki programowania

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Klasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C

Programowanie Obiektowe Ćwiczenie 4

Laboratorium 1 - Programowanie proceduralne i obiektowe

Dokumentacja do API Javy.

Podstawy Programowania 2

Współbieżność w Javie

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Katalog książek cz. 2

Wyjątki Monika Wrzosek (IM UG) Programowanie obiektowe 180 / 196

Zadanie polega na stworzeniu bazy danych w pamięci zapewniającej efektywny dostęp do danych baza osób.

Programowanie w Javie

Monitory. Jarosław Kuchta

Klasy i obiekty cz II

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Programowanie zaawansowane

Klasy cd. Struktury Interfejsy Wyjątki

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Przykładowa dostępna aplikacja w Visual Studio - krok po kroku

Kompilacja javac prog.java powoduje wyprodukowanie kilku plików o rozszerzeniu.class, m.in. Main.class wykonanie: java Main

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Rozdział 3. Zapisywanie stanu aplikacji w ustawieniach lokalnych

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Klasy i obiekty cz I Klasy, obiekty, podstawy używania obiektów

Transkrypt:

Programowanie Współbieżne C# 1

Materiały http://www.microsoft.com/express/download/ http://msdn.microsoft.com/en-us/library/aa645740(vs.71).aspx http://www.albahari.com/threading/ http://www.centrumxp.pl/ 2

Pierwsze kroki 3

Pierwsze kroki 4

Pierwsze kroki 5

Pierwsze kroki 6

Pierwsze kroki Z zestawu narzędzi wybieramy przycisk 7

Pierwsze kroki Ustawiamy przycisk 8

Pierwsze kroki We właściwościach zmieniamy nazwę przycisku jego tekst 9

Pierwsze kroki Po dwukrotnym kliknięciu otworzy nam się wygenerowany automatycznie kod programu do uzupełnienia 10

Pierwsze kroki Następnie uzupełniamy nasz kod jedną linią: MessageBox.Show("Hello world"); Kompilacja i uruchomienie F5 lub ctrl+f5 11

Wątki Kiedy przydają nam się wątki? Gdy chcemy by nasz program reagował gdy wykonuje w tle jakieś ciężkie zadanie Różnego rodzaju procesy serwery. Podczas oczekiwania na dane na jednym wątku, program może coś wykonywać na innym. Gdy mamy program, który wykonuje sporo obliczeń (np. kompresja plików multimedialnych) i chcemy je w jakiś sposób zrównoleglić. Efekt będzie odczuwalny gdy fizycznie będziemy dysponować wieloma rdzeniami. Ilość tą można sprawdzić za pomocą Environment.ProcessorCount 12

Wątki Kiedy wątki mogą nam szkodzić? Gdy będzie ich za dużo. Czas przełączania i alokacji zbyt kosztowny, Gdy zadanie wykonywane przez wątek będzie krócej trwało niż powołanie danego wątku. Gdy w pełni nie przewidzimy interakcji pomiędzy wątkami, debugowanie jest bardzo kłopotliwe. Gdy używamy dużo dysku, nie powinniśmy powoływać wiele wątków, a raczej jeden, dwa i szeregować zadania odczytu i zapisu. (ktoś próbował skopiować z płyty CD/DVD kilka plików naraz?) 13

Wątki Gdy operujemy na wątkach musimy dodać do programu using System.Threading; Każdy program ma przynajmniej jeden wątek, zwany wątkiem głównym Każdy wątek ma swój oddzielny stos więc zmienne lokalne są modyfikowane niezależnie. Zmienne globalne są współdzielone przez wątki (często wymagana synchronizacja) 14

Wątki Przykład uruchomienia metod działających jako wątki. private void naszwatekbezparametrow() MessageBox.Show("wątek ZUPELNIE bez parametrów"); private void naszwatek(object o) MessageBox.Show("jestem sobie " + Thread.CurrentThread.Name + "\nwiadomość to: " + (string)o); private void naszwatek() MessageBox.Show("wątek bez parametrów, przeciążony"); 15

Wątki Przykład uruchomienia bez parametrów Thread watek = new Thread(new ThreadStart(naszWatekBezParametrow)); //Thread watek = new Thread(naszWatekBezParametrow); //kompilator sam sobie resztę doda //Thread watek = new Thread(new ThreadStart(naszWatek)); //Thread watek = new Thread(naszWatek); //Gdy mamy przeciążone metody (bez i z parametrami kompilator nie wie czy zastosować ThreadStart czy ParameterizedThreadStart watek.start(); //jako wątek bez parametrów przy próbie Start(wiadomosc) zakończy się błędem podczas uruchomienia //string wiadomosc = "jakaś wiadomość"; //watek.start(wiadomosc); 16

Wątki Przykład uruchomienia z parametrami private void naszwatekzparametrem(object wiadomosc) MessageBox.Show((string)wiadomosc); Thread watek = new Thread(new ParameterizedThreadStart(naszWatekZParametrem)); //Thread watek = new Thread(naszWatekZParametrem); //Thread watek = new Thread(new //ParameterizedThreadStart(naszWatek)); //watek.start(); //Możliwy taki start ale nie będzie parametrów watek.start("jakaś wiadomość będąca parametrem"); 17

Wątki Przykład uruchomienia anonimowego private void naszwatekzkonkretnymparametrem(string wiadomosc) MessageBox.Show("Nasz wątek z konkretnym parametrem dostał wiadomość: \n" + wiadomosc); string zmiennawiadomosc; zmiennawiadomosc = "Wiadomość przed utworzeniem wątku"; Thread watek = new Thread(delegate() naszwatekzkonkretnymparametrem(zmiennawiadomosc); ); // zastosowanie anonimowej metody, nie musimy podawać parametru object tylko możemy konkretnego typu np. string zmiennawiadomosc = "Wiadomość po utworzeniu wątka"; // Thread watek = new Thread(delegate() MessageBox.Show("wiadomość 1"); MessageBox.Show("Wiadomość 2"); ); watek.start(); 18

Wątki Przykład uruchomienia z obiektu public class RozneWatki public void watek1() MessageBox.Show("jestem sobie wątek1"); public void watek2() MessageBox.Show("jestem sobie wątek2"); RozneWatki roznewatki = new RozneWatki(); Thread watek1 = new Thread(rozneWatki.watek1); Thread watek2 = new Thread(rozneWatki.watek2); watek1.start(); watek2.start(); 19

Wątki Nazywanie wątków pomoc w debugowaniu Thread watek = new Thread(naszWatek); watek.name = "Ot taka nazwa"; private void naszwatek() MessageBox.Show(Thread.CurrentThread.Name); 20

Wątki Wątki pierwszoplanowe i w tle Thread watek = new Thread(naszWatek); watek.isbackground = true; //gdy true zamknięcie głównego zamyka też potomny watek.start(); private void naszwatek() MessageBox.Show(Thread.CurrentThread.Name); Domyślnie IsBackground = false dlatego po zamknięciu głównej aplikacji nadal widzimy wątki z niej powstałe. Gdy ustawimy na true wyjście z wątka głównego powoduje natychmiastowe zakończenie wątków potomnych. Blok finaly jest pomijany. Jest to sytuacja nie pożądana dlatego powinniśmy poczekać na koniec wątków potomnych. Zmiana pracy z tła do pierwszoplanowej i odwrotnie nie wpływa na priorytet. 21

Wątki Priorytetowość enum ThreadPriority Lowest, BelowNormal, Normal, AboveNormal, Highest Oznacza jak dużo czasu procesora przyznane jest dla danego wątka w grupie wątków jednego procesu. Ustawienie na Highest wcale nie oznacza że będzie to wątek czasu rzeczywistego. Trzeba by było również ustawić priorytet dla procesu. Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; Jest jeszcze wyższy priorytet Realtime, wtedy nasz proces będzie działał nieprzerwanie, jednak gdy wejdzie w pętle nieskonczoną nie odzyskamy kontroli nad systemem. W przypadku gdy nasza aplikacja posiada (zwłaszcza skomplikowany) interfejs graficzny, też nie powinniśmy podnosić priorytetu, gdyż odświerzanie spowoduje zwolnienie całego systemu. 22

Wątki Wyjątki Try watek.start(); catch MessageBox.Show("błąd przy uruchamianiu"); Taki uruchomienie zwróci nam jedynie wyjątek przy uruchamianiu, nie przechwycimy wyjątku rzuconego w wątku. Wyjątki z wątków mogą zakończyć aplikację, trzeba je przechwytywać na poziomie wątków. 23

Synchronizacja Blokowanie Procesy zablokowane z powodu oczekiwania na jakieś zdarzenie, np. Sleep, Join, lock, Semaphore itp. Natychmiastowo zrzekają się czasu procesora, dodają WaitSleepJoin do właściwości ThreadState i nie kolejkują się do czasu odblokowania. Odblokowanie może nastąpić z 4 przyczyn: Warunek odblokowania został spełniony Minął timeout Został przerwany przez Thread.Interrupt Zosatł przerwany przez Thread.Abort 24

Synchronizacja Oczekiwanie Sleep i SpinWait static void Main() Thread.Sleep (0); // zrzeknięcie czasowego Thread.Sleep (1000); // uśpij na Thread.Sleep (TimeSpan.FromHours godzinę Thread.Sleep (Timeout.Infinite); do czasu przerwania. się przydzielonego kwantu 1000 ms (1)); // uśpij na 1 // śpij wiecznie :) czyli Ogólnie Sleep powoduje rezygnację wątku z czasu procesora. Wątek taki nie jest kolejkowany przez podany czas. Thread.SpinWait (100); // nic nie rób przez 100 cykli Wątek nie rezygnuje z procesora, jednak wykonuje na nim puste operacje. Nie jest w stanie WaitSleepJoin i nie może być przerwany przez Interrupt. Można zastosować gdy chcemy czekać bardzo krótko. 25 Podobnie zachowuje się wątek podczas aktywnego czekania.

Synchronizacja Oczekiwanie Join Thread watek1 = new Thread(new ParameterizedThreadStart(naszWatekZParametrem)); watek1.start("wątek z Join."); watek1.join(); Czekamy na zakończenie watku. Mechanizm, zbierania komunikatów nie jest zatrzymany, więc jak klikniemy jakiś guzik w wątku głównym to ostatecznie doczekamy się reakcji. 26

Sekcja krytyczna Kilka wątków (n_wątków) robi to samo zadanie: for (int ii = 0; ii < 1000000; ii++) licznik++; Bez zabezpieczeń wynik będzie wynosił <= n_wątków*1000000 27

Sekcja krytyczna lock private object blokowacz = new object();... for (int ii = 0; ii < 1000000; ii++) lock (blokowacz) licznik++; W danym momencie tylko jeden wątek, może przebywać w chronionym obszarze inne będą czekały w kolejce FIFO Wątki czekające są w stanie WaitSleepJoin. Wątki takie można też zakończyć przez przerwanie lub abort 28

Sekcja krytyczna Wybór obiektu który będzie blokował Musi to być typ referencyjny Zwykle jest związany z obiektami na których działamy np.: class Bezpieczna List <string> list = new List <string>(); void Test() lock (list) list.add ("Item 1");... Powinniśmy stosować obiekty które są private by uniknąć niezamierzonej interakcji z zewnątrz Z tego samego powodu nie powinniśmy stosować np. lock (this) lub lock (typeof (Widget))... Użycie obiektu do zablokowania fragmentu kodu nie powoduje automatycznie blokowania danego obiektu. lock(list1) list2.add ("Item 1");... 29

Sekcja krytyczna Monitor rozwinięcie lock Lock faktycznie jest skrótem składniowym czegoś takiego: Monitor.Enter(blokowacz); try licznik++; finally Monitor.Exit(blokowacz); Wywołanie Monitor.Exit bez uprzedniego Monitor.Enter spowoduje rzucenie wyjątku Monitor posiada też metodę TryEnter gdzie możemy podać timeout jeżeli wejdziemy przed końcem czasu to zwróci true lub false jeżeli wystąpi timout. 30

Sekcja krytyczna Interlocked operacje atomowe for (int ii = 0; ii < 1000000; ii++) Interlocked.Increment(ref licznik); Dodatkowo mamy do dyspozycji Add Dodadawanie do dwóch liczb CompareExchange porównanie i ewentualna podmiana Decrement zmniejszenie Equals czy równe Exchange Zamiana Read odczyt liczby 64b ReferenceEquals porównanie dwóch referencji 31

Sekcja krytyczna Blokowanie zagnieżdżone static object x = new object(); static void Main() lock (x) Console.WriteLine ("Zablokowałem"); Nest(); Console.WriteLine ("Odblokowałem"); //Tutaj odblokowane zupełnie static void Nest() lock (x) //Tu podwójny lock //Tu odblokowane tylko ostatnie zagnieżdżenie Wątek blokujący może blokować ile chce, jednak blokowany i tak będzie czekał na tym najbardziej zewnętrznym. 32

Sekcja krytyczna Kiedy blokować Wszędzie tam gdzie wiele wątków może mieć dostęp do wspólnych zmiennych Wszędzie tam gdzie chcemy mieć niepodzielność operacji, np. sprawdzenie warunku i wykonanie czegoś Na co uważać Nie powinniśmy zbyt dużo blokować bo ciężko analizować taki kod a łatwo spowodować DeadLock Zbyt duże fragmenty kodu wykonywane przez pojedynczy proces powodują zubożenie współbieżności. 33

Przerwanie wątku Thread.Interrupt przerywa bieżące czekanie i powoduje rzucenie wyjątku ThreadInterruptedException private void wateknieskonczony() try Thread.Sleep(Timeout.Infinite); catch (ThreadInterruptedException ex) MessageBox.Show("przechwycony wyjątek:"+ex.message); MessageBox.Show("A tu koniec"); Należy pamiętać, że przerywanie w ten sposób może być niebezpieczne, chyba, że wiemy dokładnie w którym miejscu jesteśmy i posprzątamy. 34

Przerwanie wątku Thread.Abort Działa podobnie jak Interrupt z tą różnicą, że rzuca wyjątkiem ThreadAbortException oraz wyjątek jest ponownie rzucany pod koniec bloku catch, chyba że w bloku catch zastosujemy Thread.ResetAbort(); Działanie jest podobne, jednak w przypadku Interrupt wątek przerywany jest tylko w momencie czekania, Abort może tego dokonać w dowolnym miejscu wykonywania, nawet w nienaszym kodzie. 35

Stany wątku ThreadState kombinacja bitowa trzech warstw. Uruchomienie, blokada, przerwanie wątku (Unstarted, Running, WaitSleepJoin, Stopped, AbortRequested) Pierwszoplanowość i drugoplanowość wątku (Background, Foreground) Postęp w zawieszeniu wątku (SuspendRequested, Suspended ) używane przez przestarzałe metody Ostateczny stan wątku określa się przez sumę bitową tych trzech Warstw. I tak, może być np wątek Background, Unstarted lub SuspendRequested, Background, WaitSleepJoin 36

Stany wątku W enumeracji ThreadState są też nigdy nie używane dwa stany: StopRequested i Aborted By jeszcze bardziej skomplikować, Running ma wartość 0 więc porównanie if ((t.threadstate & ThreadState.Running) > 0)... nic nam nie da Można się wspomóc IsAlive jednak zwraca false tylko przed startem i gdy się zakończy. Gdy jest zablokowany też jest true. Najlepiej napisać sobie swoją metodę: public static ThreadState SimpleThreadState (ThreadState ts) return ts & (ThreadState.Aborted ThreadState.AbortRequested ThreadState.Stopped ThreadState.Unstarted Thr eadstate.waitsleepjoin); 37

Stany wątku WaitSleepJoin Abort Wątek blokowany Unstarted Start Wątek odblokowany Abort Running Abort Requested ResetAbort Zakończenie wątku Stopped Zakończenie wątku Teoretycznie Aborted 38

Wait Handles Win32 Api dostarcza trzech klas EventWaitHandle Mutex Semaphore Wszystkie 3 bazują na abstrakcyjnej klasie WaitHandle EventWaitHandle ma dwie podklasy AutoResetEvent ManualResetEvent Różnią się one tylko sposobem wywołania konstruktora. WaitHandles pozwalają na nazwanie klas i używanie pomiędzy odrębnymi procesami 39

Wait Handles AutoResetEvent Można porównać do bramki która przepuszcza tylko jeden proces za naciśnięciem jednego guzika. Gdy bramka jest otwarta proces lub wątek który wywoła metodę WaitOne() przechodzi przez bramkę jednocześnie ją zamykając Gdy bramka jest zamknięta proces ustawia się w kolejce. Każdy inny nie zablokowany proces może odblokować bramkę za pomocą wywołania metody Set() Jedno wywołanie Set() wpuści tylko jeden proces. Gdy nie będzie procesów w kolejce, Set() otworzy bramkę Gdy bramka jest już otwarta, następne Set() są ignorowane. 40

Wait Handles AutoResetEvent EventWaitHandle czekaczka = new EventWaitHandle (false, EventResetMode.Auto); EventWaitHandle czekaczka = new AutoResetEvent (false); Powyższe dwa wywołania są równoważne. Pierwszy parametr określa czy bramka ma być podczas utworzenia otwarta. Przykład (WaitHandles) 41

Wait Handles EventWaitHandle - międzyprocesowe EventWaitHandle czekaczka = new EventWaitHandle (false, EventResetMode.Auto,"Nasza nazwa czekaczki"); Trzecim parametrem może być nazwa widziana przez wszystkie inne procesy w systemie. Gdy podczas tworzenia okaże sie że obiekt o podanej nazwie istnieje dostaniemy tylko referencję a czwarty parametr będzie false; EventWaitHandle (false, EventResetMode.Auto,"Nasza nazwa czekaczki", out czynowy); Przykład (WaitHandles) 42

Ready Go Załóżmy, że mamy taki scenariusz Główny proces ma co chwilę nowe zadania do wykonania Zadania te mają być wykonane przez wątek Za każdym razem uruchamiany jest nowy wątek Przekazywane jest zadanie Po wykonaniu pracy wątek jest kończony By zmniejszyć obciążenie wynikające z tworzenia wątków (czy nawet innych procesów) możemy postępować według poniższego algorytmu: Główny proces tworzy wątek Wątek czeka na zadanie Wykonuje zadanie Przechodzi w stan oczekiwania na kolejne zadanie 43

Ready Go Najprostsza wersja producenta i konsumenta static static static static EventWaitHandle ready = new AutoResetEvent(false); EventWaitHandle go = new AutoResetEvent(false); volatile string zadanie; void Main(string[] args) new Thread(Konsument).Start(); for (int i = 1; i <= 5; i++) //przekaż 5 razy zadanie ready.waitone(); // Czekamy na gotowość konsumenta zadanie = "a".padright(i, 'a'); // przygotowujemy zadanie go.set(); // mówimy że dane gotowe do odbioru ready.waitone(); zadanie = null; go.set(); // każemy skończyć Console.ReadKey(); static void Konsument() while (true) ready.set(); // Informujemy producenta że jesteśmy gotowi go.waitone(); // i czekamy na dane if (zadanie == null) return; // gdy dostaniemy null kończymy Console.WriteLine(zadanie); Przykład ReadyGo 44

Kolejka producent - konsument Wykorzystanie procesu drugoplanowego Producent kolejkuje elementy Konsument dekolejkuje elementy Rozwiązanie podobne do poprzedniego tylko nie blokujące class ProducentKonsument : Idisposable EventWaitHandle czekaczka = new AutoResetEvent(false); Thread konsumentwatek; Queue<string> kolejka = new Queue<string>(); public ProducentKonsument() konsumentwatek = new Thread(konsument); konsumentwatek.name = "konsumentwatek"; konsumentwatek.start(); 45

Kolejka producent - konsument void konsument() while (true) string mesg = null; lock (kolejka) if (kolejka.count > 0) mesg = kolejka.dequeue(); if (mesg == null) return; if (mesg!= null) Console.WriteLine("odebralem: " + mesg); Thread.Sleep(1000); else Console.WriteLine("no to czekam..."); // Jeżeli nie ma więcej zadań to czekaj czekaczka.waitone(); 46

Kolejka producent - konsument public void zakolejkuj(string mesg) lock (kolejka) kolejka.enqueue(mesg); czekaczka.set(); public void Dispose() zakolejkuj(null); konsumentwatek.join(); czekaczka.close(); 47

Wait Handles ManualResetEvent EventWaitHandle czekaczka = new EventWaitHandle (false, EventResetMode.Manual); EventWaitHandle czekaczka = new ManualResetEvent (false); Powyższe dwa wywołania są równoważne. Pierwszy parametr określa czy bramka ma być podczas utworzenia otwarta. Metoda Set wpuszcza wszystkich czekających lub wołających WaitOne dopóki nie zamknie się przez Reset. 48

Wait Handles Mutex Działa tak samo jak lock z tym że może być używany pomiędzy procesami i jest około 100 razy wolniejszy (przy założeniu że nie blokujemy) Tak samo jak lock zapewnia wyłączny dostęp do bloku programu pomiędzy wywołaniem WaitOne a ReleaseMutex i musi być wywołany z tego samego wątka. Zaletą jest automatyczne zwolnienie mutexa nawet gdy aplikacja się zakończy nie wywołując ReleaseMutex 49

Wait Handles Mutex static Mutex mutex = new Mutex(false, "tu.kielce.pl mutex"); private void naszwatekzmutex(object o) for (int ii = 0; ii < 1000000; ii++) mutex.waitone(); licznik++; mutex.releasemutex(); Przykład Sekajca_krytyczna1 50

Wait Handles Semaphore Semafor jest jak licznik który nigdy nie może być mniejszy od 0. Operacja WaitOne zmniejsza ten licznik o 1 jeżeli jest 0 to dany wątek czeka aż inny zwiększy za pomocą Release. W przypadku semafora, podnieść go może każdy inny wątek, nie tylko ten który go opuścił, tak jak to jest w przypadku lock czy Mutex. Semafor jest nieco szybszy od Mutexa. 51

Wait Handles Semaphore static Semaphore semafor = new Semaphore(1, 1); private void naszwatekzsemaphore(object o) for (int ii = 0; ii < 1000000; ii++) semafor.waitone(); licznik++; semafor.release(); Przykład Sekajca_krytyczna1 52

Wait Handles Wait, wait, wait... WaitHandle.SignalAndWait Jednoczesne wysłanie sygnału i czekanie. Można w ten sposób zrealizowanie np. spotkań. private static EventWaitHandle wh1 = new EventWaitHandle(false,EventResetMode.AutoReset); private static EventWaitHandle wh2 = new EventWaitHandle(false,EventResetMode.AutoReset); Jeden z wątków wywołuje: WaitHandle.SignalAndWait(wh1, wh2); Drugi z wątków wywołuje: WaitHandle.SignalAndWait(wh2, wh1); 53

Wait Handles Wait, wait, wait... WaitHandle.WaitAll(WaitHandle[] waithandles)czekaj na pozwolenie od wszystkich z waithandles WaitHandle.WaitAny(WaitHandle[] waithandles) Czekaj na pozwolenie od którego kolwiek z waithandles 54

Wait Handles ContextBoundObject Automatyczne blokowanie wywołań metod z jednej instancji klasy. using System.Runtime.Remoting.Contexts; [Synchronization] public class JakasKlasa : ContextBoundObject... CLR (Common Language Runtime) zapewnia, że tylko jeden wątek może wywołać kod tej samej instancji obiektu w tym samym czasie. Sztuczka polega na tym, że podczas tworzenia obiektu klasy JakasKlasa tworzony jest obiekt proxy przez którego przechodzą wywołania metod klasy 55 JakasKlasa.

Wait Handles ContextBoundObject Automatyczna synchronizacja nie może być stosowana do pól protect static ani klas wywodzących się od ContextBoundObject np Windows Form Trzeba też pamiętać, że nadal nie rozwiązuje nam to problemu gdy wywołamy dla kolekcji coś takiego: BezpiecznaKlasa bezpieka = new BezpiecznaKlasa();... if (bezpieka.count > 0) bezpieka.removeat (0); 56

Wait Handles ContextBoundObject Jeżeli z bezpiecznego obiektu tworzony jest kolejny obiekt to automatycznie jest on też bezpieczny w tym samym kontekscie, chyba, że postanowimy inaczej za pomocą atrybutów. [Synchronization (SynchronizationAttribute.REQUIRES_NEW)] public class JakasKlasaB : ContextBoundObject... NOT_SUPPORTED - równoważne z nieużywaniem Synchronized SUPPORTED - dołącz do istniejącego kontekstu synchronizacji jeżeli jest stworzony z innego obiektu, w innym przypadku będzie niesynchronizowany REQUIRED - (domyślny) dołącz do istniejącego kontekstu synchronizacji jeżeli jest stworzony z innego obiektu, w innym przypadku stwórz swój nowy kontekst synchronizacji REQUIRES_NEW - Zawsze twórz nowy kontekst synchronizacji 57

Delegaty i zdarzenia Obiektowy odpowiednik wskaźnika do funkcji z c/c++ klasa pochodną z klasy System.Delegate Deklaracja wygląda jak deklaracja funkcji: delegate void PrzykladowyDelegat(); //deklaracja delegatu która jest równoważna z deklaracją klasy By wykorzystać delegat musimy stworzyć nowy obiekt tej klasy. delegate ddd = new PrzykladowyDelegat(jakasFunkcja); jakasfunkcja musi być tego samego typu co delegat. Funkcjonalnie zachowuje się jak klasy wewnętrzne w javie z tym że w javie trzeba było tworzyć całą klasę tu tylko metodę. 58

Delegaty i zdarzenia //PrzykladDelegate class Program delegate void JakisDelegat(); // metoda zgodna z deklaracją delegatu static void jakasfunkcja() System.Console.WriteLine("Jakas Funkcja!? Przecieże to był delegat!"); static void Main(string[] args) JakisDelegat ddd = new JakisDelegat(jakasFunkcja); // w tym miejscu delegujemy wywołanie metody jakasfunkcja() ddd(); Console.ReadLine(); 59

Delegaty i zdarzenia Zdarzenia (events) są formą komunikacji informowania innych, że wystąpiła jakaś sytuacja. Realizowane są przy pomocy delegatów. Przykład eventa wraz argumentami: public delegate void TikTakEventHandler(object sender, TikTakEventArgs e); public event TikTakEventHandler cykevent; public class TikTakEventArgs : EventArgs public int ktorecykniecie; public bool czywiecznie; 60

Delegaty i zdarzenia Zasygnalizowanie zdarzenia: TikTakEventArgs tta = new TikTakEventArgs(); tta.czywiecznie = true; for (int ii = 0;ii<ileRazy;ii++) tta.ktorecykniecie = ii; if (cykevent!=null) cykevent(this,tta); Thread.Sleep(1000); Przykład: PrzykladEventa 61

Delegaty i zdarzenia Cross-Thread W wielowątkowej aplikacji okienkowej nie można używać metod ani pól kontrolek, które nie zostały stworzone w danym wątku. Gdy chcemy zapisać coś na formatce z innego wątku private void niebezpieczneliczydlo() for (int liczba = 0; liczba < 20; liczba++) labellicznik.text = liczba.tostring();... Thread wateklicz = new Thread(niebezpieczneLiczydlo); wateklicz.start(); dostaniemy: Przykład: przykladcrossthread Cross-thread operation not valid: Control 'labellicznik' accessed from a thread other than the thread it was created on. Trzeba posłużyć się pewną sztuczką, którą podpowiada MS. 62

Delegaty i zdarzenia private void liczydlobezpieczne() for (int liczba = 0; liczba < 20; liczba++) if (this.labellicznik.invokerequired) // jest w innym wątku więc wymaga ZapiszTekst zapdel = new ZapiszTekst(zapiszTekst); //wywołuje delegata zapdel przekazując mu tablicę //parametrów w tym przypadku jeden parametr this.invoke(zapdel, new object[] liczba.tostring()); else // Gdy jest w tym samym wątku this.labellicznik.text = liczba.tostring(); Thread.Sleep(1000); Przykład: przykladcrossthread 63

Apartment Threading Jest logicznym kontenerem zawierającym: Jeden wątek (Single-Threded Apartment) Wiele wątków (Multi-Threded Apartment) Apartment może zawierać zarówno wątki jak i obiekty Kontekst Synchronizacji mógł tylko obiekty Obiekty takie są przypisane do Apartment'u przez cały okres trwania. Obiekty w kontekście synchronizacji mogą być wołane przez dowolne wątki (ale w trybie exclusive) Obiekty w Apartment mogą być wywołane tylko przez wątki w tym samym Apartmencie. 64

Apartment Threading Jeżeli można by było przedstawić obrazowo kontener jako bibliotekę, obiekty jako książki a wątki jako osoby to: W przypadku kontekstu synchronizacji do biblioteki wchodził by sobie ktokolwiek ale zawsze pojedynczo (nie może być dwóch osób w bibliotece) W przypadku apartmentów mamy pracowników przypisanych do biblioteki. Single. Jest jeden bibliotekarz i do niego odwołujemy się by coś przeczytał i nam powiedział co w danej książce jest Multi. Jest wiele bibliotekarzy. 65

Apartment Threading Sygnalizowanie bibliotekarzowi, że chcemy skorzystać z jakiejś książki (obiektu) nosi nazwę marshalling (przekazywanie?). Metoda jest przekazywana (marshal) poprzez pracownika biblioteki i wykonywana na obiektach w bibliotece Marshalling jest zaimplementowany w bibliotekarzu przez system komunikatów w Windows Forms i jest przekazywane automatycznie Jest to mechanizm który cały czas sprawdza zdażenia związane z myszką i klawiaturą. Gdy nie zdążą być obsłużone są kolejkowane (FIFO). 66

Apartment Threading Wątki.Net są automatycznie przypisane do multithread-appartment chyba, że chcemy by było inaczej wtedy: Thread t = new Thread (...); t.setapartmentstate (ApartmentState.STA); Lub class Program [STAThread] static void Main()... 67

Apartment Threading Gdy nasza aplikacja to czysty kod.net Apartment nie ma znaczenia. Typy z System.Windows.Forms korzystają z kodu Win32 przeznaczonego do pracy w Single Thread Apartment. Z tego powodu w programach tego typu wymagane jest [STAThread]. 68

Background Worker Jest pomocną klasą z System.ComponentModel która dostarcza nam następującej funkcjonalności Flaga cancel do zasygnalizowania końca, zamiast Abort Standardowy protokół do do raportowania postępu, zakończenia i przerwania pracy Implementacja IComponent pozwalająca na umieszczenie w VS Designerze. Łapanie wyjątków w wątku workera Możliwość zapisywania postępu bezpośrednio na formatkę w innym wątku (nie ma problemu z wywołaniem Cross-thread), nie musimy używać Control.Invoke 69

Background Worker Model tego typu wykorzystuje identyczną składnię, jak asynchroniczne delegaty Aby użyć BacgroundWorkera wystarczy poinformować go jaka metoda ma być wykonana w tle i wywołać RunWorkerAsync() Wątek główny kontynuuje działanie a w tle wykonywana jest funkcja zgłoszona do BackgroundWorkera. Gdy BW skończy sygnalizuje to zdarzeniem RunWorkerCompleted 70

Background Worker Zróbmy sobie formatkę jak niżej: Pola nazwane będą textboxczas oraz textboxilosc Guzik nazwany po prostu buttonstart Dodajemy backgroundworkera przeciągając go z toolsów i zmieniamy jego nazwę na backgroundworkerliczydlo 71

Background Worker Dwukrotnie klikając w BW otworzy nam się kod wykonywany podczas zdarzenia DoWork Uzupełniamy go private void backgroundworkerliczydlo_dowork(object sender, DoWorkEventArgs e) //uzyskaj obiekt wejsciowy ParametryDwa parametry = (ParametryDwa)e.Argument; for (int i = 0; i < parametry.ilosciteracji; i++) Console.WriteLine("właśnie wykonuję iterację " + i); System.Threading.Thread.Sleep(parametry.czasUspienia); Klasa parametry: class ParametryDwa public int czasuspienia,ilosciteracji; public ParametryDwa(int _czasuspienia, int _ilosciteracji) czasuspienia = _czasuspienia; ilosciteracji = _ilosciteracji; 72

Background Worker Dwukrotnie klikając w buttonstart otwiera nam się kod wykonany po kliknięciu w guzik (do uzupełnienia): private void buttonstart_click(object sender, EventArgs e) try //uzyskaj dane z formatki int czas = int.parse(textboxczas.text); int ilosc = int.parse(textboxilosc.text); //umieść to w obiekcie do wysyłki ParametryDwa param = new ParametryDwa(czas, ilosc); backgroundworkerliczydlo.runworkerasync(param); catch (Exception ex) MessageBox.Show(ex.Message); Uruchamiamy (F5), wypełniamy, klikamy start Backgroundworker wykonuje swoją pracę a my możemy dalej obsługiwać aplikację 73

Background Worker Gdy chcemy się dowiedzieć o końcu zadania i przekazać jakieś parametry wystarczy obsłużyć zdarzenie: RunWorkerCompleted. private void backgroundworkerliczydlo_runworkercompleted(object sender, RunWorkerCompletedEventArgs e) MessageBox.Show("Praca została wykonana\n" + e.result); oraz w DoWork przygotować wynik private void backgroundworkerliczydlo_dowork(object sender, DoWorkEventArgs e) //uzyskaj obiekt wejsciowy ParametryDwa parametry = (ParametryDwa)e.Argument; for (int i = 0; i < parametry.ilosciteracji; i++) Console.WriteLine("właśnie wykonuję iterację " + i); System.Threading.Thread.Sleep(parametry.czasUspienia); string komunikat = "W sumie " + (parametry.ilosciteracji * parametry.czasuspienia) + " milisekund"; e.result = komunikat; 74 Przykład: BackgroundWorker