W informatyce kontekst zadania (procesu, wątku itp.) to minimalny zestaw informacji opisujących stan tego zadania, które muszą zostać zachowane, aby można było przerwać wykonanie zadania i później wznowić je dokładnie w tym samym miejscu. Pojęcie to ma szczególne znaczenie dla zadań przerywalnych: po przerwaniu procesor zapisuje kontekst bieżącego zadania, przełącza się do obsługi przerwania lub innego zadania, a następnie (po wyborze zadań do wykonania) przywraca odpowiedni kontekst, aby wznowić wykonywanie przerwanego zadania. Im mniejszy i bardziej lokalny jest kontekst, tym krótsze opóźnienie związane z przełączaniem.
Co wchodzi w skład kontekstu zadania?
- Rejestry procesora — licznik rozkazów (Program Counter / Instruction Pointer), rejestry ogólnego przeznaczenia, wskaźnik stosu (Stack Pointer), rejestry statusowe (flags). W zależności od architektury może to obejmować też rejestry specyficzne dla trybu użytkownika i trybu jądra.
- Rejestry specjalne i koprocesorowe — rejestry FPU, SIMD (SSE/AVX), rejestry kontrolne procesora (np. CR3 na x86 wskazujący tablicę stron), rejestry sterujące i inne stany sprzętowe istotne dla zadania.
- Pamięć używana przez zadanie — mechanizmy adresowania, mapowania pamięci (tablice stron, przestrzeń adresowa). Przy przełączaniu między procesami może być konieczna zamiana kontekstu pamięciowego (np. ustawienie innego CR3), co wiąże się z kosztami (np. opróżnienie/TLB).
- Dane zarządzane przez system operacyjny — struktury opisujące zadanie (np. PCB, task_struct), kolejki, stany blokad, kontekst jądra związany z zadaniem oraz opis otwartych zasobów (np. deskryptory plików), które tworzą tzw. kontekst procesu.
- W niektórych systemach operacyjnych — dodatkowe rejestry kontrolne używane przez system do zarządzania zadaniami lub sprzętowe mechanizmy wspomagające przełączanie (np. Task State Segment w starszych implementacjach x86).
Co zwykle nie jest częścią podstawowego kontekstu
- Pamięć masowa (pliki) — zawartość plików na dysku nie jest częścią standardowego kontekstu procesora. System może jednak wykonywać dodatkowe zapisy stanu na dysk w celach checkpointingu lub migracji procesu, ale to jest rozszerzony, trwały obraz stanu, a nie standardowy mechanizm przełączania kontekstu podczas działania systemu.
Przełączanie kontekstu — jak przebiega?
- W momencie decyzji o zmianie zadania (np. wywołanie planisty, przerwanie, blokada I/O) system: zapisuje aktualny stan (rejestry, wskaźniki, stan jądra) do struktury procesu (PCB).
- Planista wybiera kolejne zadanie do wykonania zgodnie z polityką (priorytety, fairness, affinitiy).
- System ładuje z pamięci stan nowego zadania — przywraca rejestry, ustawia wskaźnik stosu i licznik rozkazów, ewentualnie przełącza przestrzeń adresową (tablice stron).
- Procesor kontynuuje wykonywanie nowego zadania od przywróconego punktu.
Różnice między przełączaniem procesów a wątków
- Procesy zwykle mają oddzielną przestrzeń adresową i własne tablice stron, więc przełączenie między procesami często wiąże się z przełączeniem kontekstu pamięciowego (kosztownym, np. TLB flush).
- Wątki (z tej samej przestrzeni adresowej) współdzielą pamięć i zasoby procesu; przełączanie między wątkami tego samego procesu jest zwykle lżejsze — nie wymaga zmiany przestrzeni adresowej, trzeba zapisać/odtworzyć głównie rejestry i stos.
- Istnieją też zielone wątki i biblioteczne mechanizmy współbieżności realizowane w przestrzeni użytkownika — ich przełączanie może odbywać się bez udziału jądra (bardzo niskie koszty), ale tracą one z reguły na integracji z mechanizmami blokowania sprzętowego i planowania jądra.
Koszty przełączania kontekstu i czynniki wpływające
- Bezpośrednie koszty — zapisywanie i przywracanie rejestrów, aktualizacja struktur jądra, wywołania procedur planowania.
- Pośrednie koszty — utrata lokalności pamięci, opróżnienie lub odświeżenie TLB, strata zawartości pamięci podręcznej procesora (cache), konieczność napełnienia pipeline’u CPU. To często stanowi większy narzut niż same instrukcje zapisu/rejestru.
- Czynniki wpływające — architektura procesora, liczba i rodzaj rejestrów do zapisu (np. rozmiar stanu FPU/SIMD), polityka jądra (częstotliwość preempcji), rozmiar przestrzeni adresowej oraz mechanizmy sprzętowe wspierające szybkie przełączanie.
Optymalizacje i techniki redukujące narzut
- Lenistwo przy zapisie stanu FPU/SIMD — zapis/odtworzenie stanów koprocesora tylko wtedy, gdy jest to konieczne (lazy FPU save).
- Afinitet procesora — przypisywanie zadań do określonych rdzeni, aby zmniejszyć utratę danych w cache.
- Wątki zamiast procesów — tam, gdzie to możliwe, użycie wątków (shared address space) zamiast nowych procesów zmniejsza koszt przełączania.
- Planowanie przyjazne lokalności — scheduler dba o to, żeby zadania wracały na ten sam rdzeń/gdzie ich dane są w cache.
- Użytkownik-poziom przełączania (user-space threading) — pozwala na bardzo szybkie przełączanie, ale kosztem integracji z jądrem (np. blokujący system call może zablokować wątek użytkownika).
Kiedy stosuje się checkpointing i migrację?
Checkpointing to mechanizm zapisu rozszerzonego obrazu stanu procesu (wraz z pamięcią, deskryptorami, stanami sieci itp.) na trwały nośnik — stosowany do odtwarzania po awarii lub migracji procesu między maszynami. Jest to operacja odrębna od codziennego mechanizmu przełączania kontekstu — trwała i kosztowna, wykonywana rzadziej.
Podsumowanie
Kontekst zadania to zbiór informacji niezbędnych do wznowienia wykonania zadania: rejestry, wskaźniki stosu, stany koprocesorów, struktury jądra i (w szerszym sensie) dane opisujące przestrzeń adresową. Przełączanie kontekstu jest nieodłącznym elementem wielozadaniowości, ale jego koszt zależy od tego, ile stanu trzeba zapisać i przywrócić oraz od wpływu na cache i TLB. Projektanci systemów i programiści stosują różne techniki (wątki, afinity, optymalizacje zapisu stanów) by minimalizować ten narzut tam, gdzie ma to znaczenie dla wydajności.