Poniższy artykuł pochodzi z serii Przygotowań do egzaminu 70-536.
Zaczynamy rozdział nr 7 w naszym Training Kicie, który będzie dotyczył wątków. Od tej pory przejdziemy z tematów łatwiejszych do nieco trudniejszych:) Dziś wpis bardzo krótki, wprowadzający tylko do wątków.
Po co nam wątki? Dzięki wątkom możemy np. uruchomić jakiś kod w tle, nie blokując w międzyczasie innych czynności naszego programu. Jednak używanie wielowątkowości jest dosyć skomplikowane i w pewnych określonych sytuacjach zamiast zwiększać wydajność, zmniejsza ją. No ale oczywiście więcej mamy plusów korzystając z wątków niż minusów:)
Używanie klasy ThreadPool
Aby uruchomić metodę w tle, używamy klasy System.Threading.ThreadPool. Poniższy kod pokazuje jak używać statycznej metody ThreadPool.QueueUserWorkItem (która zawiera się w przestrzeni System.Threading), do odpalenia własnej metody w nowym wątku.
1: static void Main(string[] args)
2: {
3: //Kolejka zadań
4: ThreadPool.QueueUserWorkItem(ThreadProc);
5: Console.WriteLine("Główny wątek coś robi a następnie zostaje uśpiony.");
6: Thread.Sleep(1000);
7: Console.WriteLine("Koniec głównego wątku.");
8: Console.ReadLine();
9: }
10: static void ThreadProc(Object stateInfo)
11: {
12: Console.WriteLine("Pula wątków.");
13: }
Za pomocą przeciążonej QueueUserWokItem możemy również przekazać obiekt do metody. Poniższy kod jest rozszerzeniem poprzedniego. Różni się tym, że do metody ThreadProc dostarczymy obiekt stringa:
1: static void Main(string[] args)
2: {
3: string state = "Hello, world!";
4: //Kolejka zadań
5: ThreadPool.QueueUserWorkItem(ThreadProc,state);
6: Console.WriteLine("Główny wątek coś robi a następnie zostaje uśpiony.");
7: Thread.Sleep(1000);
8: Console.WriteLine("Koniec głównego wątku.");
9: Console.ReadLine();
10: }
11: static void ThreadProc(Object stateInfo)
12: {
13: //musimy rzutować na stringa parametr
14: string state = (string)stateInfo;
15: Console.WriteLine("Pula wątków."+ state);
16: }
Metodę ThreadPool.QueueUserWorkItem możemy wywołać wiele razy, nawet jeśli wątki mają wykonać się jednocześnie. Możemy więc zamienić ostatni kod na taki:
1: static void Main(string[] args)
2: {
3: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 1");
4: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 2");
5: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 3");
6: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 4");
7: ThreadPool.QueueUserWorkItem(ThreadProc,"Thread 5");
8:
9: Console.WriteLine("Główny wątek coś robi a następnie zostaje uśpiony.");
10: Thread.Sleep(1000);
11:
12: Console.WriteLine("Koniec głównego wątku.");
13:
14: }
15: static void ThreadProc(Object stateInfo)
16: {
17: //musimy rzutować na stringa parametr
18: string state = (string)stateInfo;
19: Console.WriteLine("Pula wątków."+ state);
20: }
Wątki główne i w tle
Nasz główny wątek aplikacji jest uważany jako foreground thread, czyli ten wątek “na wierzchu”, głowny.Dopóki wątek ten jest aktywny, nasza aplikacja działa. Wszystkie wątki, które działają w tle zostają automatycznie anulowane, w momencie zakończenia głównego wątku. Aby sprawdzić, czy bieżący wątek jest wątkiem w tle czy tym foreground możemy użyć bool’owskiej właściwości Thread.CurrentThread.IsBackground. Poniższy kod prezentuje wywołanie metody ThreadProc jako wątek background lub foreground. Aby wywołać metodę jako wątek foreground, wywołujemy ją normalnie. Żeby stworzyć wątek w tle, wywołujemy ThreadPool.QueueUserWorkItem:
1: static void Main(string[] args)
2: {
3: //wątki, które będą traktowane jako background
4: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 1");
5: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 2");
6:
7: //wątek wywołany normalnie, potraktowany będzie jako foreground
8: ThreadProc("Thread 3"); // Called as part of the foreground thread
9:
10: //kolejny jako background
11: ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 4");
12:
13: Console.WriteLine("Main thread does some work, then sleeps.");
14: Thread.Sleep(1000);
15: Console.WriteLine("Main thread exits.");
16:
17: Console.ReadLine();
18: }
19:
20: static void ThreadProc(Object stateInfo)
21: {
22: //musimy rzutować na stringa parametr
23: string state = (string)stateInfo;
24:
25: //sprawdzamy czy bieżący wątek jest traktowany jako background
26: if (Thread.CurrentThread.IsBackground)
27: Console.WriteLine("Hello from backgroud thread: " + state);
28: else
29: Console.WriteLine("Hello from foreground thread: " + state);
30: }
To by było na tyle dzisiaj :) W środę Dawid opisze zarządzanie wątkami.
Kolejny artykuł z serii to 70-536 Managing Threads