W ostatnim poście wspomniałem o minimalnej liczbie wątków. Istnieje również górny próg, określający ile maksymalnie może zostać stworzonych wątków. Zbyt niski próg oraz zła architektura może spowodować bardzo trudny w znalezieniu błąd a mianowicie deadlock. Wyobraźmy sobie następującą sekwencję zdarzeń:
- Wątek T0 (lub główny, nie ma znaczenia) dodaje zadanie do puli.
- Stworzone zadanie tworzy n nowych zadań.
- T0 czeka aż wszystkie n zadań zostanie wykonanych (wait).
Następnie przyjmijmy, że w tych n wątkach, któryś czeka na zakończenie jakiegoś innego. Jeśli wątek numer n-2 czeka na n-1 to dojdzie do deadlock. W przypadku, gdy limit jest ustawiony na 50, a zadań do wykonania jest 70 z tym, że np. zadanie numer 60 czeka na wykonanie 61 to będziemy mieli do czynienia z zakleszczeniem. Jeśli jest to niejasne, zobrazujmy to kodem:
class Program { static ManualResetEvent _blocker=new ManualResetEvent(false); static void Main(string[] args) { int maximal, temp; ThreadPool.GetMaxThreads(out maximal, out temp); Console.WriteLine("Max threads: {0}",maximal); for (int i = 0; i < maximal + 1; i++) { ThreadPool.QueueUserWorkItem(Run); } ThreadPool.QueueUserWorkItem(Signal); Console.ReadLine(); } private static void Signal(object state) { Console.WriteLine("Signaling"); _blocker.Set(); } private static void Run(object state) { _blocker.WaitOne(); Console.WriteLine("Run"); } }
W .NET 2.0 i 3.5 domyślnie maksymalna liczba wątków na procesor (rdzeń) to 250. W .NET 1.0 było to tylko 25. Powyższy kod najpierw tworzy wątki, które dopiero zostaną wykonane gdy ManualResetEvent wyśle sygnał. W tym problem, że wyczerpie to limit wolnych wątków i Signal nigdy nie zostanie wykonany.
Od wersji .NET 4.0 ta liczba ma charakter dynamiczny. W zależności od dostępnych zasobów może zostać zwiększona lub zmniejszona (mam na myśli wciąż wartość domyślną).
Problem może się wydawać niewarty uwagi ale w praktyce bardzo łatwo go popełnić. Jeśli korzystamy z zewnętrznych komponentów nie mamy pojęcia jak bardzo pula jest obciążona. Co jeśli mamy dostępne tylko 2 wątki? W takiej sytuacji, może okazać się, że bardzo prosty problem spowoduje deadlock.
Powyższy przykład pokazuje również problem zaprezentowany w poprzednim wpisie – zbyt niska wartość minimalnej liczby wątków. Stworzenie 250 wątków zajmie ponad kilka minut!