Code Review: Thread.Suspend

Każdy wątek posiada metodę Suspend, która wstrzymuje jego wykonywanie. Ktoś mógłby napisać  takiego “potworka”:

class Program
{        
   static void Main(string[] args)
   {
       Thread thread=new Thread(Run);
       thread.Start();
       
       Thread.Sleep(1000);
       thread.Suspend();
       Thread.Sleep(5000);
       thread.Resume();

   }
   static private void Run()
   {
       while(true)
       {
           Console.WriteLine("Running...");
       }            
   }
}

Używanie Suspend jest bardzo złą praktyką i może spowodować wiele problemów. Od którejś wersji .NET Framework, metoda ta została nawet oznaczona jako Obselete. Dlaczego, jest to takie złe podejście?

Zastanówmy się, po co możemy chcieć zawiesić wątek na kilka sekund. Skoro tworzymy go, chcemy w końcu aby wykonał jak najszybciej swoje operacje. Nie ma sensu wstrzymywania go bo oczywiście efekt będzie taki, że operacja zostanie później wykonana. Ktoś może zasugerować, że być może wątek powinien zostać wstrzymany ponieważ na jakimś etapie, pewne dane mogą być jeszcze niegotowe. Jeśli tak to mamy do czynienia z czystą synchronizacją i jest to skrajnie zły scenariusz użycia Suspend.

Do synchronizacji służą takie klasy jak Semaphore, Monitor, Mutex, ManualResetEvent etc. W przypadku Suspend, największy problem to fakt, że nie wiemy kiedy dokładnie wątek zostanie wstrzymany. Może to zdarzyć się to w każdym w momencie. Co jeśli wątek A zawiesza wątek B, który aktualnie jest w sekcji krytycznej (lock, semafor) M? W takim przypadku, o ile wątek A, chce również uzyskać dostęp do M, będziemy mieli deadlock.

Wątek zawieszony oczywiście wymusza zmianę kontekstu. Problem w tym, że wciąż on zajmuje zasoby. Jeśli taki wątek nie zostanie wznowiony potem, mamy memory leak – zasoby będą w pamięci aż do momentu zamknięcia procesu.

W 99.9% Suspend jest skrajnie złą praktyką. W jakich zatem sytuacjach jest to dopuszczalne a nawet stanowi jedyne rozwiązanie? Głównie narzędzia programistyczne, debuggery itp. korzystają z tego. Klasycznym przykładem jest Garbage Collector, który musi wstrzymać wątki w celu znalezienia obiektów nieosiągalnych. Podobnie robi wiele debuggerów i tym podobnych narzędzi. To co jednak cechuje powyższe przykłady to brak wykonywania kolejnych blokad czy jakieś logiki, bazującej na wspólnych danych. Wszystkie te przykłady zatrzymują wątek tylko po to, aby pobrać jakieś dane od nich – stacktrace, graf obiektów itp. W praktyce  są to skrajne sytuacje i osobiście nie spotkałem się z nimi w pracy – nigdy nie musiałem skorzystać z Suspend.

3 thoughts on “Code Review: Thread.Suspend”

  1. Dla Suspend widzę jeszcze jedno zastosowanie: w grach, gdy w tle wykonywane są niekrytyczne obliczenia w osobnym wątku (np. AI analizuje posunięcia gracza i buduje długofalową taktykę) – w sytuacji, gdy wydajność gry spada, takie obliczenia można czasowo zawiesić, w prosty i w miarę bezinwazyjny sposób. Podobnie we wszelkich “wypełniaczach CPU” typu analiza statyczna wykonywana przez IDE – gdy potrzebna jest wydajność, zawieszamy operację niezależnie od stanu.

  2. @Bogumił: to jest przykład synchronizacji – dużo lepiej skorzystać z ManualResetEvent w tym przypadku.

  3. Pingback: sitelinks4seo.com

Leave a Reply

Your email address will not be published.