Harmonogram wątków
Każdy wątek ma przypisany priorytet wątku. Wątki utworzone w środowisku uruchomieniowym języka wspólnego są początkowo przypisywane priorytet .ThreadPriority.Normal Wątki utworzone poza środowiskiem uruchomieniowym zachowują priorytet, jaki mieli przed wejściem do środowiska zarządzanego. Możesz uzyskać lub ustawić priorytet dowolnego wątku z właściwością Thread.Priority .
Wątki są zaplanowane do wykonania na podstawie ich priorytetu. Mimo że wątki są wykonywane w środowisku uruchomieniowym, wszystkie wątki są przypisywane wycinki czasu procesora przez system operacyjny. Szczegóły algorytmu planowania używanego do określania kolejności wykonywania wątków różnią się w zależności od systemu operacyjnego. W niektórych systemach operacyjnych wątek o najwyższym priorytcie (z tych wątków, które można wykonać) jest zawsze zaplanowany do pierwszego uruchomienia. Jeśli wszystkie wątki z tym samym priorytetem są dostępne, harmonogram będzie przechodził przez wątki o tym priorytcie, dając każdemu wątkowi stały wycinek czasu, w którym ma zostać wykonany. Jeśli wątki o wyższym priorytcie są dostępne do uruchomienia, wątki o niższym priorytcie nie są wykonywane. Jeśli nie ma więcej wątków możliwych do uruchomienia w danym priorytcie, harmonogram przechodzi do następnego niższego priorytetu i planuje wątki o tym priorytcie na potrzeby wykonywania. Jeśli wątek o wyższym priorytcie staje się uruchamiany, wątek o niższym priorytcie jest wywłaszczony, a wątek o wyższym priorytcie może być wykonywany po raz kolejny. Oprócz tego system operacyjny może również dynamicznie dostosowywać priorytety wątków, ponieważ interfejs użytkownika aplikacji jest przenoszony między pierwszym i tłem. Inne systemy operacyjne mogą zdecydować się na użycie innego algorytmu planowania.
Przykład
Oto przykład wykonywania 9 wątków na wszystkich 5 poziomach priorytetu z Thread.Priority wyliczenia, w którym ostatnie 5 jest na najwyższym poziomie priorytetu. Ponadto mamy obsługę wywołania zwrotnego z poprzedniego artykułu, który w tym kontekście pokazuje, że kolejność inicjowania wątku i priorytetyzacji może nie zawsze być odzwierciedlana w kolejnym kodzie ani w kolejności uruchamiania wykonywania procesów. Oznacza to, że widzimy tutaj równoległy charakter wykonywania kodu i pokaz przypisanych wycinków czasu procesora przez system operacyjny dla każdego wątku. Wyróżnia to wpływ i kontrolę środowiska, w którym działają wątki. W tym przypadku z pewnością widzimy, że wątki o najwyższym priorytcie są rzeczywiście traktowane priorytetowo w wykonaniu.
Poniższy kod spowoduje wygenerowanie dowolnych wyników dla każdego wykonania. Jednak typowe wzorce sekwencji priorytetów, które są uruchamiane, można zaobserwować po wielokrotnym uruchomieniu kodu i przeanalizowaniu danych wyjściowych.
namespace snippets;
public class SchedulingThreads
{
public void RunMultipleThreadsOnDifferentPriorities()
{
var threadsList = new List<Thread>(9);
// Initialize 9 threads. 5 with Highest priority, and the first 4 from Lowest to Normal range.
for (int i = 0; i < 9; i++)
{
var thread = new Thread(() => { new ThreadWithCallback(Callback).Process(); });
if (i > 3)
thread.Priority = ThreadPriority.Highest;
else
thread.Priority = (ThreadPriority)i;
threadsList.Add(thread);
}
threadsList.ForEach(thread => thread.Start());
}
public void Callback(ThreadPriority threadPriority)
{
Console.WriteLine($"Callback in {threadPriority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}.");
}
public class ThreadWithCallback
{
public ThreadWithCallback(Action<ThreadPriority> callback)
{
this.callback = callback;
}
public Action<ThreadPriority> callback;
public void Process()
{
Console.WriteLine($"Entered process in {Thread.CurrentThread.Priority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}.");
Thread.Sleep(1000);
Console.WriteLine($"Finished process in {Thread.CurrentThread.Priority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}.");
if (callback != null)
{
callback(Thread.CurrentThread.Priority);
}
}
}
// The example displays the output like the following:
// Entered process in Highest priority. ThreadId: 9.
// Entered process in Highest priority. ThreadId: 12.
// Entered process in Normal priority. ThreadId: 6.
// Entered process in BelowNormal priority. ThreadId: 5.
// Entered process in Lowest priority. ThreadId: 4.
// Entered process in AboveNormal priority. ThreadId: 7.
// Entered process in Highest priority. ThreadId: 11.
// Entered process in Highest priority. ThreadId: 10.
// Entered process in Highest priority. ThreadId: 8.
// Finished process in Highest priority. ThreadId: 9.
// Finished process in Highest priority. ThreadId: 12.
// Finished process in Highest priority. ThreadId: 8.
// Finished process in Highest priority. ThreadId: 10.
// Callback in Highest priority. ThreadId: 10.
// Finished process in AboveNormal priority. ThreadId: 7.
// Callback in AboveNormal priority. ThreadId: 7.
// Finished process in Lowest priority. ThreadId: 4.
// Callback in Lowest priority. ThreadId: 4.
// Finished process in Normal priority. ThreadId: 6.
// Callback in Highest priority. ThreadId: 9.
// Callback in Highest priority. ThreadId: 8.
// Callback in Highest priority. ThreadId: 12.
// Finished process in Highest priority. ThreadId: 11.
// Callback in Highest priority. ThreadId: 11.
// Callback in Normal priority. ThreadId: 6.
// Finished process in BelowNormal priority. ThreadId: 5.
// Callback in BelowNormal priority. ThreadId: 5.
}