Procesy i wątki
Jacek Matulewski
7 kwietnia 2015 Programowanie Windows
http://www.fizyka.umk.pl/~jacek/dydaktyka/winprog/
Definicje
• Proces to egzemplarz/instancja programu z własną wirtualną przestrzenią adresową, kontekstem bezpieczeństwa, dostępem do obiektów systemowych, unikalnym identyfikatorem (PID), przynajmniej jednym wątkiem (tzw. głównym, primary)
• Wątek to kod wykonywany w obrębie procesu; proces może uruchomić wiele wątków, wykonywanych współbieżnie. Wątki współdzielą przestrzeń adresową procesu, mając dostęp do
wspólnych zmiennych i struktur (tu ostrożnie).
• MSDN: https://msdn.microsoft.com/en-
us/library/windows/desktop/ms684841(v=vs.85).aspx
• Pula wątków (ang. thread pool) – na poziomie aplikacji
• UMS (ang. user-mode scheduler) w obrębie aplikacji, lekki
Uruchamianie procesów
• Tworzenie procesów to de facto uruchamianie programów
• Wcześniej poznaliśmy funkcje WinExec i ShellExecute
• Obie otaczają funkcję CreateProcess
• Proces zwraca strukturę PROCESS_INFORMATION
zawierającą uchwyt procesu, uchwyt głównego wątku, PID, i identyfikator głównego wątku.
• Dodatkowo CreateProcessAsUser ,
CreateProcessWithLogon (np. dodatkowe uprawnienia)
• Czekanie na zakończenie procesu WaitForSingleObject
• Sprzątanie: CloseHandle dla uchwytu procesu i uchwytu wątku (nie zamyka procesu, tylko sprząta)
Uruchamianie procesów
• Przykładowy kod:
bool Wynik=CreateProcess(
NULL, //plik exe aplikacji
lFileName,//polecenie uruchamiające program
NULL, //korzystamy z domyślnego opisu bezpieczeństwa procesu NULL, //korzystamy z domyślnego opisu bezpieczeństwa wątku false, //czy uchwyty dziedziczone w procesie
priority, //priorytet
NULL, //korzystanie ze zmiennych środowiska aplikacji wywołującej lDirectory, //katalog bieżący aplikacji
&startupInfo, //parametry uruchomienia aplikacji
&lProcessInformation //informacje o uruchomionej aplikacji );
• Zmienne środowiskowe zastąpił rejestr systemu Windows
Demo: CreateProcess
• Klasa CCreateProcess
• Uruchamianie procesu – Execute, ExecuteAndWait
• Przykład 1: uruchamianie okna konsoli
• Przykład 2: uruchamianie kalkulatora i minimalizowanie okna do czasu
zamknięcia
• Rozszerzenie w BCB:
TControlProcess
Demo: ShellExecute
• Przed CreateProcess była funkcja WinExec (Win16)
• Dla kontrastu funkcja ShellExecute (wysokopoziomowa)
• Funkcja powłoki (ShellAPI), m.in. dla Exploratora Windows
• F. ShellExecute jest bardzo często używana w praktyce, mniejsza liczba argumentów, możliwość edytowania
dokumentów (aplikacje skojarzone przez rozszerzenia plików)
Priorytet procesów
• Odczytanie i zmiana priorytetu procesu
GetPriorityClass i SetPriorityClass
• Wymagane uprawnienia PROCESS_QUERY_INFORMATION
• Zwraca jedną z wartości:
REALTIME_PRIORITY_CLASS HIGH_PRIORITY_CLASS
ABOVE_NORMAL_PRIORITY_CLASS NORMAL_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS IDLE_PRIORITY_CLASS
• Priorytet to wskazówka dla planisty systemu Windows
Obsługa procesów
• Maksymalne uprawnienia PROCESS_ALL_ACCESS
• TerminateProcess - przerywanie procesu i jego wątków (asynchroniczna, podobnie jak CreateProcess)
• ExitProcess – z wnętrza procesu
(return w procedurze wątku też woła tę funkcję)
• GetCurrentProcess – pobieranie niby-uchwytu do bieżącego procesu (stałej interpretowana w funkcjach)
• GetProcessId, GetCurrentProcessId –
„prawdziwe” PID wskazanego procesu i bieżącego procesu
• GetProcessInformation, GetProcessIoCounters, GetProcessTimes, Get/SetProcessAffinityMask
• IsImmersiveProcess (czy proces z Windows Store App)
Tworzenie wątków
• Funkcja CreateThread
(zob. też CreateRemoteThread – w innym procesie)
HANDLE uchwytWątku = CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//wskaźnik do SECURITY_ATTRIBUTES SIZE_T dwStackSize, //początkowy rozmiar stosu w bajtach
LPTHREAD_START_ROUTINE lpStartAddress, //uruchamiana funkcja typu: DWORD WINAPI ThreadProc(LPVOID lpParameter);
LPVOID lpParameter, //parametr przesyłany do funkcji DWORD dwCreationFlags,
LPDWORD lpThreadId //zwraca ID wątku );
• Dobrze mieć uprawnienia THREAD_ALL_ACCESS
Priorytety wątków
• Analogiczne, jak w przypadku procesów
• Także priorytety wątków mogą być zmieniane po utworzeniu
• Priorytety wątków są względne wobec priorytetów procesów
• Funkcje SetThreadPriority i GetThreadPriority
Priority boost
(dla wątków o priorytecie NORMAL_PRIORITY_CLASS)
• Planista przyspiesza procesy/wątki będące w pierwszym planie
• Planista zwiększa wątek okna, które ma focus
• Wątek jest wznawiany po użyciu funkcji Wait..
• Przyspieszenie takie można to zablokować używając funkcji SetThreadPriorityBoost (podobnie SetProcess..)
Wstrzymywanie wątków
• Usypianie wątku: Sleep na określoną liczbę milisekund
• Wstrzymywanie i wznawianie wątku:
SuspendThread, ResumeThread
• Jeżeli funkcja SuspendThread została wywołana trzy razy, tyle samo musi być wywołana funkcja ResumeThread.
• Wątki można tworzyć funkcją CreateThread od razu wstrzymane – flaga CREATE_SUSPENDED
Przerywanie wątków
• Zła praktyka: TerminateThread – przerywanie bez dania szansy wątkowi na dokończenie procedury
(w tym na zwolnienie zasobów, m.in. pamięci).
Jeżeli wątek jest w sekcji krytycznej – może nigdy nie zostać zwolniona.
Procedura wątku nie jest powiadamiana o zamknięciu.
• Lepiej powiadomić procedurę wątku, że powinna się zakończyć np. przesłać do procedury jako parametr uchwyt zdarzenia
(funkcja CreateEvent) i wywołać go z funkcji wywołującej (funkcja SetEvent).
• TerminateThread vs. ExitThread
Synchronizacja wątków
• Zasadnicze problemy programowania współbieżnego to
1) określenie, które zmienne powinny być współdzielone, a które
dostępne tylko z wątku oraz 2) wydzielenie fragmentów, które powinny być wykonane tylko przez jeden wątek na raz (np. zapis do pliku).
• Funkcje Wait.., np. WaitForSingleObject,
• Zdarzenia (CreateEvent, SetEvent),
• Sekcje krytyczne (ang. critical sections),
• Slim Reader/Writer (SRW) locks,
• MemoryBarrier – makro implementujące barierę I/O,
• Muteksy (ang. mutex od mutual exclusion) – między procesami,
• Semafory (sekcja krytyczna dla więcej niż jednego wątku).
Sekcje krytyczne
• Zakres: tylko w obrębie jednego procesu
• Obiekt CRITICAL_SECTION – identyfikuje sekcję
• Inicjowanie i usuwanie obiektu sekcji krytycznej:
InitializeCriticalSection, DeleteCriticalSection
• Wejście do sekcji krytycznej EnterCriticalSection – inne wątki zatrzymują się na tej funkcji, jeżeli mają ten sam argument identyfikujący sekcję, dopóki bieżąca nie opuści sekcji
• Wyjście z sekcji: LeaveCriticalSection (do sekcji krytycznej wchodzi następny wątek)
• TryEnterCriticalSection – wersja asynchroniczna
Muteksy
• Zakres: w obrębie sesji systemu – działa między procesami
• Można użyć, aby umożliwić tylko jedną instancję aplikacji
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
try {
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, 0, "Unikalny");
if (!hMutex) hMutex = CreateMutex(0, 0, "Unikalny");
else return 0;
//Kod aplikacji (m.in. tworzenie wątku UI) ReleaseMutex(hMutex);
}
catch { ... } return 0;
}
Synchronizacja - problemy
• Problem ucztujących filozofów
• Na dwóch wątkach - przelew
• Scenariusz czytelników i pisarzy
• Dwa wątki z jednym zasobem – problem producent-konsument
Włókna (ang. fibers)
• Wątki są kontrolowane przez system, włókna – przez sam kod
• Wywłaszczanie wątków – algorytm szeregujący może
wstrzymać jeden wątek, aby uruchomić lub wznowić inny (inicjatywa po stronie systemu, a nie wątku).
To może przerwać działanie ważnej operacji lub pozostawić aplikację w niedookreślonym stanie (koncept thread safety)
• Włókno to lekki „wątek” bez wywłaszczania; włókno samo decyduje, kiedy inne może przejąć procesor (odpowiedzialność programisty). Same włókna nie dają współbieżności.
• Włókna mogą być przenoszone do innego wątku (w obrębie procesie). Wątek może wykonywać wiele włókien.
Włókna (ang. fibers)
• Pierwsze włókno musi być utworzone z wątku za pomocą funkcji ConvertThreadToFiber. Tylko włókna mogą uruchamiać inne włókna.
• Tworzenie nowych włókien CreateFiber z istniejącego
• Gdy włókno się kończy, kończy się też wątek. Aby temu zapobiec SwitchToFiber.
• Pobieranie i czyszczenie danych używanych przez włókno:
GetFiberData, DeleteFiber.
Przykładowe pytania
• Czym są proces i wątek?
• Czy możliwe jest utworzenie procesu jako użytkownik inny, niż uruchamiający bieżący proces?
• Jakie funkcje służą do zarządzania działaniem wątków?
Jakie funkcje służą do kontroli priorytetu procesu i wątku?
• Synchronizacja wątków w obrębie procesów i na poziomie systemu?
• Sekcje krytyczne
• Współdzielenie zasobów przez wątki.
„Zakliszcz” – problem ucztujących filozofów