Rozwidlenie wywołania systemowego w C

Fork System Call C



Wywołanie systemowe fork() służy do tworzenia procesów potomnych w programie C. fork() jest używany tam, gdzie w aplikacji wymagane jest przetwarzanie równoległe. Funkcja systemowa fork() jest zdefiniowana w nagłówkach sys/types.h oraz unistd.h . W programie, w którym używasz forka, musisz również użyć wywołania systemowego wait(). Wywołanie systemowe wait() służy do oczekiwania w procesie nadrzędnym na zakończenie procesu potomnego. Aby zakończyć proces potomny, w procesie potomnym używane jest wywołanie systemowe exit(). Funkcja wait() jest zdefiniowana w nagłówku sys/czekaj.h a funkcja exit() jest zdefiniowana w nagłówku stdlib.h .

Rys 1: Podstawowy przepływ pracy fork()

Rys 1: Podstawowy przepływ pracy fork()







W tym artykule pokażę, jak używać wywołania systemowego fork() do tworzenia procesów potomnych w C. Zacznijmy więc.



fork() Składnia i zwracana wartość:

Składnia funkcji systemowej fork() jest następująca:



widelec pid_t(próżnia);

Funkcja systemowa fork() nie przyjmuje żadnego argumentu. Zwraca liczbę całkowitą typu pid_t .





W przypadku powodzenia fork() zwraca PID procesu potomnego, który jest większy niż 0. Wewnątrz procesu potomnego zwracana jest wartość 0. Jeśli fork() się nie powiedzie, zwraca -1.

Prosty fork() Przykład:

Poniżej podano prosty przykład fork():



#włączać
#włączać
#włączać
#włączać
#włączać

intGłówny(próżnia) {
pid_t pid=widelec();

Jeśli(pid== 0) {
printf ('Dziecko => PPID: %d PID: %d ',getppid(),getpid());
Wyjście (EXIT_SUCCESS);
}
w przeciwnym razie Jeśli(pid> 0) {
printf ('Rodzic => PID: %d ',getpid());
printf („Czekam na zakończenie procesu dziecka. ');
czekać(ZERO);
printf („Proces dla dzieci zakończony. ');
}
w przeciwnym razie {
printf ('Nie można utworzyć procesu podrzędnego. ');
}

powrótEXIT_SUCCESS;
}

Tutaj użyłem fork(), aby utworzyć proces potomny z procesu głównego/nadrzędnego. Następnie wydrukowałem PID (identyfikator procesu) i PPID (identyfikator procesu nadrzędnego) z procesu podrzędnego i nadrzędnego. W procesie nadrzędnym wait(NULL) służy do oczekiwania na zakończenie procesu potomnego. W procesie potomnym exit() służy do zakończenia procesu potomnego. Jak widać, PID procesu nadrzędnego jest PPID procesu potomnego. Tak więc proces potomny 24738 należy do procesu nadrzędnego 24731 .

Możesz także użyć funkcji, aby uczynić swój program bardziej modułowym. Tutaj użyłem procesZadanie() oraz rodzicZadanie() funkcje odpowiednio dla procesów potomnych i nadrzędnych. Tak właśnie używa się fork().

#włączać
#włączać
#włączać
#włączać
#włączać

próżniadzieckoZadanie() {
printf ('Witaj świecie ');
}

próżniarodzicZadanie() {
printf ('Główne zadanie. ');
}

intGłówny(próżnia) {
pid_t pid=widelec();

Jeśli(pid== 0) {
dzieckoZadanie();
Wyjście (EXIT_SUCCESS);
}
w przeciwnym razie Jeśli(pid> 0) {
czekać(ZERO);
rodzicZadanie();
}
w przeciwnym razie {
printf („Nie można utworzyć procesu podrzędnego”.);
}

powrótEXIT_SUCCESS;
}

Wyjście powyższego programu:

Uruchamianie wielu procesów potomnych za pomocą fork() i Loop:

Możesz również użyć pętli, aby utworzyć tyle procesów podrzędnych, ile potrzebujesz. W poniższym przykładzie utworzyłem 5 procesów potomnych za pomocą pętli for. Wydrukowałem również PID i PPID z procesów potomnych.

#włączać
#włączać
#włączać
#włączać
#włączać

intGłówny(próżnia) {
dla(inti= 1;i<= 5;i++) {
pid_t pid=widelec();

Jeśli(pid== 0) {
printf ('Proces potomny => PPID=%d, PID=%d ',getppid(),getpid());
Wyjście (0);
}
w przeciwnym razie {
printf ('Proces nadrzędny => PID=%d ',getpid());
printf ('Oczekiwanie na zakończenie procesów podrzędnych... ');
czekać(ZERO);
printf ('proces potomny zakończony. ');
}
}

powrótEXIT_SUCCESS;
}

Jak widać, identyfikator procesu nadrzędnego jest taki sam we wszystkich procesach potomnych. Więc wszystkie należą do tego samego rodzica. Wykonują również w sposób liniowy. Jedna po drugiej. Kontrolowanie procesów potomnych to skomplikowane zadanie. Jeśli dowiesz się więcej o programowaniu systemu Linux i jego działaniu, będziesz mógł kontrolować przepływ tych procesów w dowolny sposób.

Przykład z prawdziwego życia:

Różne złożone obliczenia matematyczne, takie jak generowanie skrótów md5, sha256 itp., wymagają dużej mocy obliczeniowej. Zamiast obliczać takie rzeczy w tym samym procesie, co główny program, możesz po prostu obliczyć skrót w procesie podrzędnym i zwrócić skrót do procesu głównego.

W poniższym przykładzie wygenerowałem 4-cyfrowy kod PIN w procesie potomnym i wysłałem go do procesu nadrzędnego, czyli programu głównego. Następnie wydrukowałem stamtąd kod PIN.

#włączać
#włączać
#włączać
#włączać
#włączać

intzdobądź PIN() {
// użyj PPID i PID jako nasiona
srand (getpid() +getppid());
intsekret= 1000 + wiersz () % 9000;
powrótsekret;
}

intGłówny(próżnia) {
intfd[2];
rura(fd);
pid_t pid=widelec();

Jeśli(pid> 0) {
blisko(0);
blisko(fd[1]);
po(fd[0]);

intsekretny numer;
rozmiar_treadBytes=czytać(fd[0], &sekretny numer, rozmiar(sekretny numer));

printf („Oczekiwanie na kod PIN... ');
czekać(ZERO);
printf ('Przeczytane bajty: %ld ',readBytes);
printf ('PIN: %d ',sekretny numer);
}
w przeciwnym razie Jeśli(pid== 0) {
blisko(1);
blisko(fd[0]);
po(fd[1]);

intsekret=zdobądź PIN();
pisać(fd[1], &sekret, rozmiar(sekret));
Wyjście (EXIT_SUCCESS);
}

powrótEXIT_SUCCESS;
}

Jak widać, za każdym razem, gdy uruchamiam program, otrzymuję inny 4-cyfrowy kod PIN.

Tak więc w zasadzie używa się wywołania systemowego fork() w Linuksie. Dziękuję za przeczytanie tego artykułu.