Wątki
Przegląd zagadnień
Wątki
Uruchamianie wątków
Wątki – dalsze informacje
Synchronizacja
Podsumowanie
Pytania sprawdzające
Laboratorium
Wątki
Najczęstszą przyczyną wykorzystania
wątków jest sytuacja, w której
program ma wykonywać kilka
czynności jednocześnie
Do zarządzania wątkami służy w C#
przestrzeń nazw System.Threading
Decydując się na stworzenie kilku
wątków warto zastanowić się nad tym,
czy nie spowoduje to spadku
wydajności pracy programu
Uruchamianie wątków
Wątek można utworzyć jako
egzemplarz klasy Thread, podając jako
argument egzemplarz delegata. Służy
do tego klasa ThreadStart, wskazująca
na określoną przez programistę
metodę
Składnia:
Do uruchomienia wątku potrzebujemy
jeszcze:
Thread
watek = new
Thread
(new
ThreadStart
(nazwa_funkcji));
watek.
Start
();
Uruchamianie wątków – przykład
Jeżeli przykładowo zdefiniujemy w aplikacji
dwie funkcje funkcja1 oraz funkcja2, to
możemy wykorzystać je w wątkach:
Procesor będzie przełączał między wątkami,
naprzemiennie wykonując działania zawarte
w funkcja1 oraz w funkcja2
Cały proces będzie z reguły trwał do
momentu zakończenia działania przez
funkcje
Thread w1 = new Thread(new ThreadStart(funkcja1));
Thread w2 = new Thread(new ThreadStart(funkcja2));
w1.Start();
w2.Start();
Wątki – dalsze informacje (1)
Niekiedy pojawia się potrzeba, by jeden
z wątków zaczekał na wynik drugiego –
można wówczas wykorzystać dołączanie
pierwszego wątku (w1) do drugiego (w2)
Wykonanie powyższej instrukcji w
metodzie wątku w1 spowoduje
wstrzymanie wątku w1 do czasu
zakończenia wątku w2
Umieszczenie wątków w kolekcji pozwala
na wykorzystanie instrukcji foreach,
dzięki czemu program zakończy się po
wykonaniu wszystkich wątków
w2.Join();
Wątki – dalsze informacje (2)
Mechanizmem służącym do zatrzymania
wątku na pewien czas jest metoda
Thread.Sleep, której argumentem może być
liczba milisekund lub obiekt timeSpan
Od wątku można zażądać, by sam
zakończył działanie:
poprzez ustawienie sprawdzanej co jakiś czas
opcji
wywołując metodę Thread.Interrupt
wykorzystując Thread.Abort (zaowocuje to
wyrzuceniem wyjątku ThreadAbortException,
który należy obsłużyć)
Słowo o synchronizacji (1)
W programie niekiedy pojawia się
sytuacja, w której byłoby dobrze
zapewnić dostęp do pewnego
elementu tylko jednemu wątkowi w
danym czasie – na przykład
zapisującemu dane w pliku
Do stworzenia kolejki dostępowej
można wykorzystać blokadę na
obiekcie, pełniącą funkcję
synchronizacji
Słowo o synchronizacji (2)
W języku C# mamy trzy podstawowe
możliwości:
klasa Interlocked z metodami Increment oraz
Decrement pozwala na zwiększanie i
zmniejszanie licznika, zapewniając jednocześnie
synchronizację, wywoływane:
Bardziej ogólny mechanizm synchronizacji
możemy uzyskać stosując mechanizm blokady,
pozwalając na oznaczenie sekcji krytycznej w
kodzie
Mechanizm monitorów
int temp =
Interlocked.Increment
(ref licznik)
int temp2 =
Interlocked.Decrement
(ref licznik)
Synchronizacja – przykład
blokady
Kod C#
public void Zwiekszenie()
{
try
{
while (licznik < 100)
{
int temp;
lock (this)
{
temp = licznik;
temp++;
Thread.Sleep(1);
licznik = temp;
}
}
}
}
Synchronizacja – monitory – idea
Monitory zostały przygotowane z myślą o
bardziej skomplikowanych sytuacjach
Pozwalają one zdecydować, kiedy ma się
zacząć i zakończyć synchronizacja, a także
oczekiwać na zakończenie działania innego
fragmentu kodu
Do rozpoczęcia synchronizacji wykorzystuje
się metodę Enter() z nazwą obiektu, do
którego chcemy zablokować dostęp;
przydatne są także metody Wait() –
pomagająca kontrolować kolejność działania
wątków oraz Pulse() informująca czekające
wątki o możliwości restartu czy Exit() na
oznaczenie końca kontrolowanego kodu
Problemy synchronizacji
W przypadku zastosowania własnych
mechanizmów synchronizacji, można
natknąć się na dwa ważne problemy:
Sytuacja wyścigu – gdy powodzenie działania
programu zależy od niekontrolowanej kolejności
wykonywania się dwóch niezależnych wątków –
rozwiązaniem może być połączenie wątków lub
odpowiednie użycie monitora
Zakleszczenie – może się zdarzyć, gdy dwa
wątki oczekują na zwolnienie zasobów – każdy
oczekuje na zakończenie działania przez drugi –
można temu zapobiec pozwalając wątkom
zajmować jak najmniejsze fragmenty kodu lub
po prostu stosować zwalnianie lub zajmowanie
wszystkich zasobów
Podsumowanie
Wykorzystanie wątków pozwala na
wykonywanie przez program wielu
czynności w tym samym czasie
Ważną rolę pełni synchronizacja,
opierająca się na umożliwianiu dostępu
tylko jednemu wątkowi w tym samym
czasie
Pytania sprawdzające
Dlaczego warto stosować wątki?
W jaki sposób można zapewnić
synchronizację licznika przy dwóch
różnych wątkach?
Wymień metody synchronizacji.
Laboratorium