Podczas tworzenia procesu system operacyjny zapisuje wszystkie
informacje o nowym procesie, takie jak identyfikator procesu, dane o
rozmieszczeniu w pamięci, poziom uprzywilejowania, itp., w odpowiednich
strukturach danych. W systemie UNIX – deskryptor procesu.
Powstanie nowego deskryptora procesu w systemie UNIX
oznacza, że pojawił się nowy pretendent do zasobów systemu komputerowego.
Od tego momentu system operacyjny, podczas udostępniania zasobów
komputera, musi uwzględnić potrzeby nowego procesu.
W wyniku stworzenia nowego procesu, system operacyjny przydziela
procesowi określony obszar pamięci, a następnie ładuje w to miejsce zawartość
odpowiedniego pliku wykonywalnego z pamięci masowej oraz,
jeśli istnieje taka konieczność, dokonuje odpowiednich zmian w programie,
zależnie od rozmieszczenia w pamięci. W tym zakresie podsystem zarządzania
procesami ściśle współpracuje z podsystemami zarządzania pamięcią oraz
systemem plików.
Tworzenie nowego procesu w systemie UNIX odbywa się poprzez
wywołanie funkcji systemowej fork(). Proces wywołujący tą funkcję
określany jest mianem procesu macierzystego, natomiast nowo utworzony –
procesem potomnym. Funkcja tworzy nowy proces będący „klonem” procesu
macierzystego. Proces potomny posiada identyczny kontekst jak proces
macierzysty, lecz ma przydzielony inny identyfikator. Od tego momentu w
obydwu procesach wykonywane są współbieżnie te same programy, poczynając
od następnej instrukcji po funkcji fork(). Funkcja fork() wraca różne
wartości w procesie macierzystym i procesie potomnym: w procesie
macierzystym – identyfikator procesu potomnego, w procesie potomnym – 0
(zero). Uproszczony algorytm realizowany przez funkcję fork() można
przedstawić następująco:
wejście: brak
wyjście: w procesie macierzystym PID (ang.
Process Identifier) potomka
w procesie potomnym 0
{
sprawdź dostępność zasobów jądra;
pobierz wolną pozycję w tablicy procesów, określ
unikatowy PID;
sprawdź, czy użytkownik nie wykonuje zbyt wielu
procesów;
zaznacz, że potomek jest w stanie „tworzony”;
skopiuj dane z pozycji w tablicy procesów
związanej z procesem macierzystym do pozycji
związanej z procesem potomnym;
utwórz w pamięci kopię kontekstu procesu
macierzystego (u-obszar, program, dane, stos);
if (wykonywany proces jest procesem macierzystym)
{
zmień stan potomka na „gotowy do wykonania”;
return(PID potomka);
}
else
{
return(0);
}
}
W wyniku wykonania funkcji fork(), w procesie potomnym
wykonywany jest ten sam program co w procesie macierzystym, co z
praktycznego punktu widzenia wydaje się bezsensowne. Stworzenie nowego
procesu ma praktyczne znaczenie jedynie w przypadku, gdy w procesie
potomnym zostanie wykonany nowy program. W systemie UNIX jest to
realizowane przy pomocy wywołania jednej z funkcji należących do grupy
exec(), które powodują załadowanie do procesu nowego programu,
zapisanego na dysku w postaci pliku wykonywalnego. W związku z tym
programy wywołujące funkcję systemową fork() posiadają najczęściej
następującą budowę:
pid=fork();
if (pid == 0)
{operacje wykonywane w procesie potomnym
exec(plik zawierający obraz nowego procesu)}
else
{operacje wykonywane w procesie macierzystym}