Programowanie
Aplikacji Lokalnych w Środowisku .NET
Architektura systemu, jądro systemu, obiekty jądra, uchwyty
Wielozadaniowość, procesy, zadania, wątki, szeregowanie zadań
Zarys architektury systemu
Systemowe procesy pomocnicze np. menedźer sesji,
proces logowania
Procesy usługowe
Aplikacje użytkownika:
Win 32 win16
DOS POSIX/
OS/2
Podsystemy środowiskowe
win32***
OS/2 POSIX
biblioteki podsystemów
tryb użytkownika tryb jądra System okien***
Grafika***
Centrum wykonawcze *
jądro * sterowniki urządzeń Warstwa niezalezna od sprzętu HAL **
*ntoskrnl.exe/ntkrnlpa.exe, ntdll.dll, ** hal.dll,
*** kernel32.dll, adwapi32.dll,user32.dll, gdi32.dll, win32k.sys, csrss.exe
Obiekty systemowe
◼
Tworzone i zarządzane przez system
◼
Mogą być współdzielone przez procesy
◼
Użytkownik nie odwołuje się bezpośrednio do obiektu, manipuluje nim za
pośrednictwem uchwytu
Brak dostępu kodu użytkownika do obiektu (bezpieczeństwo)
Czasu życia obiektu kontrolowany przez
system (zliczanie referencji)
Obiekty jądra
Tablica uchwytów
Tablica uchwytów
2 1
h = 2
h = 6
Jądro
h = CreateXXX(”Nazwa”,..., sd, ...)
h = OpenXXX(”Nazwa”,..., sdo, ...)
Wielozadaniowość
Wielozadaniowość:
◼ wywłaszczanie wątków
◼ priorytety dostępu do procesora
◼ przetwarzanie w tle:
dodatkowe wątki procesu
(peekMessage)
❑ Obiekty systemowe – prymitywy wielozadaniowości:
❑ proces - program w trakcie wykonywania
❑ wątek - podstawowy wykonywalny składnik procesu
❑ zadanie (job) – grupa procesów zarządzana razem
❑ włókna
❑ Prymitywy .Net:
❑ Zadanie (task)
❑ Async/Await
Proces
❑
Obiekt jądra reprezentujący proces
❑
Przestrzeń adresowa przydzielona procesowi (oddzielna dla poszczególnych procesów – w Win 9x procesy wspołdzieliły obszar niskiej
pamięci)
❑
Proces obejmuje co najmniej jeden wątek – wątek główny
◼
Monitorowanie procesow
• ProcessExplorer.- stan procesów w systemie
• TaskManager
• WMI
Kończenie procesu
❑ ExitProces() - z wnętrza procesu
❑ TerminateProcess()
❑ Zakończenie wszystkich wątków typu foreground -
>Exit/TerminateThread()
◼ Dawniej powrót z funkcji głównej procesu
Pot. problem: destruktory obiektów
◼ Unieważnienie uchwytów procesu/utworzonych/otwartych obiektów (likwidowane gdy # = 0)
◼ Obiekt procesu zostaje zasygnalizowany
◼ Kod wyjścia zgodny z argumentem
Exit/TerminateProcess() –> GetExitCode(hprocess, ...)
System.Diagnostics.Proces
❑ ProcessName, BasePriority, EnableRaisingEvents,
StartInfo, StartTime, ExitCode, ExitTime, HasExited, Id ..., Processes
❑ Modules, MainModule, MainWindowHandle, MainWindowTitle...
❑ MaxWorkingSet, MinWorkingSet,
NonpagedSystemMemorySize, PeakVirtualMemorySize, PagedMemorySize, TotalProcessorTime,
UserProcessorTime....
❑ PriorityBoostEnabled, PrivilegedProcessorTime ...
❑ StandardInput, StandardOutput, StandardError ...
❑ Handle, Threads ...
System.Diagnostics.Process
❑
Start()
❑
WaitForExit(), Kill()
❑
GetProcesses(), GetProcessesById(), Processes
❑
Process.ProcessStartInfo
❑ FileName, Arguments, PriorityClass
❑ CreateNoWindow, ErrorDialog, UseShellExecute, WindowStyle, WorkingDirectory
❑ RedirectStandardInput, RedirectStandardError, RedirectStandardOutput
❑ WorkingDirectory, WindowStyle
System.Diagnostics.Process
◼
Start()
◼
Start(ProcessStartInfo info)
◼
Start(string fileName, string arguments)
◼
Start(string fileName, string userName,
◼
SecureString password, string domain )
...
Process - monitorowanie
◼ TotalProcessorTime, UserProcessorTime, VirtualMemorySize, WorkingSet
◼ Process. WaitForExit
◼ Process.WaitForInputIdle
◼ Exited -> event
Zadania (Job objects)
◼ Zarządzanie grupą procesów
❑ Monitorowanie grupy:
• TotalUser / TotalKernelTime,
Total / ActiveProcesses / TotalTerminatesProcesses, TotalPageFaults
❑ Ograniczenia wspólne dla grupy procesów – „model piaskownicy”
Czas/pamięć per process/zadanie, Liczba aktywnych procesów
Dopuszczalne CPU, Priorytet, względna część czasu
Wylogowywanie/zamykanie systemu, dostęp do schowka
Zmiana parametrów systemu / ekranu
Tworzenie desktpów/ dostęp do obiektów USER spoza zadania
• DIE_ON_UNHANDLED_EXCEPTION ->
SEM_NOGPFAULTERRORBOX
Maska nakładana na SID
◼ Wymagane wołanie API
Zadania (Job objects) WINAPI
◼ tworzenie nowego zadania: CreateJobObject
◼ otwarcie zadania: OpenJobObject
◼ przypisanie procesu AssignProcessToJobObject ( -> CREATE_SUSPENDED)
tej operacji nie można cofnąć
◼ likwidacja zadania CloseHandle
◼ zakończenie wszyskich stowarzyszonych procesów TerminateJobObject
◼ informacje o zadaniu Set/QueryInformationJobObject
◼ Informacje o procesach bez zadań GetProcessIoCounters
.NET vs API
◼ Wołanie funkcji unmanage – wymaga ich zaimportowania:
[DllImport("msvcrt.dll")]
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest {
[DllImport("msvcrt.dll")]
public static extern int puts(string c);
[DllImport("msvcrt.dll")]
internal static extern int _flushall();
public static void Main() {
puts("Test");
_flushall();
} }
MSDN -> Platform Invoke Tutorial
Powiadomienia WINAPI
Przekroczenie limitu czasu -> zasygnalizowanie zadania (i domyślnie zabicie procesów składowych->)
Monitorowanie zdarzeń -> porty dokańczania GetQueuedCompletitionInfo
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO JOB_OBJECT_MSG_END_OF_PROCESS_TIME JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT JOB_OBJECT_MSG_JOB_MEMORY_LIMIT
JOB_OBJECT_MSG_NEW_PROCESS JOB_OBJECT_MSG_EXIT_PROCESS
JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS JOB_OBJECT_MSG_END_OF_JOB_TIME
Wątki wykonania
◼ Współdzielą przestrzeń adresową ( procesu )
◼ Indywidualny
stan rejestru
zestaw zmiennych lokalnych
TLS (System.Threading.ThreadLocal<T> )
◼ Dużo mniej kosztowne niż proces
◼ Znacznie łatwiejsza komunikacja
◼ Dużo słabsza separacja niż procesów
◼ Stan wątku: IsAlive
System.Threading.Thread
Thread t = new Thread ( () => Console.WriteLine ("Hello!") );
t.Start();
Name, Priority, ThreadState
IsAlive, IsBackground, IsThreadPoolThread CurrentThread, CurrentPrincipal
Threads
Start (), Join () ,
Sleep (), Resume (), Suspend (), SpinWait () Abort(), ResetAbort (), Interrupt (),
VolatileRead (), VolatileWrite() GetDomain (),
GetData (), AllocateNamedDataSlot (), AllocateDataSlot ()
System.Threading ... classes
AutoResetEvent Interlocked
ManualResetEvent Monitor
Mutex
ReaderWriterLock
RegisteredWaitHandle WaitHandle
Timer
ThreadPool
XXXXException
wykonywanie oczekiwanie
wstrzymanie
GetMessage Sleep
SuspendThread
CREATE_SUSPENDED
ResumeThread SuspendThread
szeregowanie wątków
synchronizacja
Przełączanie wątków wykonania
Szeregowanie zadań
❑
Wykonywany jest wątek o najwyższym priorytecie
❑
Po zawieszeniu/wykorzystaniu czasu uaktualniany jest jego kontekst
❑
Wybierany jest kolejny wątek o najwyższym priory- tecie gotowy do wykonania (być może ten sam)
❑
Sporadycznie wybierane są również wątki o niskim priorytecie
❑
Długość kwantu czasu:
równy kwant d. każdego procesu ok 20ms
dłuższy dla proces.
pierwszoplan. o priorytecie Normalny
Zawieszanie wątkow
❑ Wywołania Suspend i Resume powinny być zbilansowane
❑ API: SwitchToThread() – umożliwia wznowienie watek o niższym priorytecie np. dla zwolnienie przez niego
zasobu
❑ Zawieszenie wszystkich wątków – pot. problem
dynamika wątków (powstawanie/usuwanie) wątków
Kończenie wątków
❑ Interupt (wyjątek ThreadInterruptedException zostanie rzucony przy najbliższym przejściu w stan zablokowany wait, sleep, lub join)
❑ Abort rzuca wyjątek ThreadAbortException – moze byc obsluzony ale automatycznie jest wyrzucany ponownie po zakonczeniu catch
❖ Ani Interupt ani Abort nie dzialaja na watki czekajace na unamanged wait. Na wait managed watek jest
wybudzany.
Nieosłużone wyjątki
nie zatrzymuja wątków z puli
w watkach powodują terminowane wątku
Dla .Net>=2.0 powodują terminowanie procesu
Powinny być obsłużone!!!
◼ AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(
CurDomain_MyHandler);
◼ Niezalecane wlaczenie zachowania legacy
<legacyUnhandledExceptionPolicy enabled="1"/>
SEH – StructuralExceptionHandling – niezarzadzalny handler - obejmuje każdy wątek
Foreground vs Background
Foreground utrzymują proces przy życiu, Background: nie Przy zatrzymywaniu Background z powodu zamykania
aplikacji nie jest rzucany wyjątek Przy zwolnieniu AppDomain wyjatek
AppDomainUnloadedException) jest rzucany dla obu typów wątków
Wątki z puli są typu Background Thread.IsBackground = true/false
Proces > App Domain >Thread
Izolacja
Zabezpieczenia
Kontrolowane wyładowanie
Można załadować assembly do oddzielnej AppDomain
Priorytet procesu
❑ zmiana/pobranie priorytetu Process.PriorityClass
◼ proces w tle: IDLE_PRIORITY_CLASS
◼ obniżony prioryt: BELOW_NORMAL_PRIORITY_CLASS
◼ proces normalny: NORMAL_PRIORITY_CLASS
◼ podwyższony priorytet: ABOVE_NORMAL_PRIORITY_CLASS
◼ wysoki priorytet: HIGH_PRIORITY_CLASS
◼ proces czasu rzeczywistego: REALTIME_PRIORITY_CLASS
Priorytet wątku
❑ zmiana/pobranie priorytetu: Thread.Priority
◼ THREAD_PRIORITY_IDLE
◼ THREAD_PRIORITY_LOWEST
◼ THREAD_PRIORITY_BELOW_NORMAL
◼ THREAD_PRIORITY_NORMAL
◼ THREAD_PRIORITY_ABOVE_NORMAL
◼ THREAD_PRIORITY_HIGHEST
◼ THREAD_PRIORITY_TIME_CRITICAL
Efektywny priorytet
❑ jest określony przez kombinację priorytetów procesu i wątku
1 1
1 1
1 16
Iddle
2 4
6 8
11 22
Lowest
3 5
7 9
12 23
Below n.
4 6
8 10
13 24
Normal
5 7
9 11
14 25
Above n.
6 8
10 12
15 26
Highest
15 15
15 15
15 31
Critical
Low Below
Normal Above
High Real
time
P r o c e s y
W ą t k i
Dynamiczny priorytet
❑
timer/mysz/klawiatura – mogą wymuszać dynamiczną zmianę priorytetu wątku (dla wątków o priorytecie bazowym 0-15)
❑
w Win NT/2K/XP użytkownik może decydować o dynamicznej zmianie prorytetu
Process.PriorityBoostEnabled
Włókna
◼ Przenoszenie aplikacji z UNIXa
◼ Wątek może obejmować wiele włókien
◼ Tylko jedno włókno jest wykonywane na raz
◼ Przełączenie wiąże się z zapamiętaniem kontekstu, stanu rejestrów itd
◼ Przełączanie jest zarządzane przez kod użytkownika
◼ Brak wywłaszczania na poziomie włókien (dostępne jest wywłaszczanie na poziomie wątków)
◼ Włókna są obsługiwane w trybie użytkownika (a nie jądra)
Tworzenie włókien WINAPI
Pierwsze włókno:
PVOID ConvertThreeadToFiber(PVOID pvParam) Następne: PVOID CreateFiber(DWORD dwStackSize,
PFIBER_START_ROUTINE pfnStartAdress, PVOID pvParam)
Wynik: adres kontekstu wykonania
Pobranie parametru włókna:
PVOID GetFiberData()
Punkt wejścia do włókna:
VOID WINAPI FiberFunc(PVOID pvParam) { ... }
Szeregowanie włókien
Zmiana bieżącego włókna:
void SwitchToFiber(PVOID pvFiberExecutionContext) Pobranie bieżącego włókna:
PVOID GetCurrentFiber() Kończenie włókna:
void DeleteFiber(PVOID pvFiberExecutionContext)