2012-01-23 15 views
7

Zrozumiałem, że: 1) waitpid służy do czekania na śmierć dziecka, a następnie odbiera SIGCHLD i status wyjścia dziecka itp. 2) Kiedy mamy obsługę sygnału dla SIGCHLD, robimy jeszcze więcej rzeczy związane z oczyszczaniem dziecka lub innych rzeczy (do programisty), a następnie zrobić waitpid, aby dziecko nie poszło zombie, a następnie powrócić.Używanie waitpid lub sigaction?

Czy potrzebujemy mieć zarówno 1, jak i 2 w naszych programach, gdy wykonujemy fork/exec i dziecko wraca? Jeśli mamy Zarówno SIGCHLD uzyskuje pierwszy, więc procedura obsługi sygnału nazywa się pierwszy, a tym samym jego waitpid nazywa się powodzeniem i nie waitpid w kodzie procesu nadrzędnego następująco:

my_signal_handler_for_sigchld 
{ 
do something 
tmp = waitpid(-1,NULL,0); 
print tmp (which is the correct value of the child pid) 
} 

int main() 
{ 
    sigaction(SIGCHLD, my_signal_handler_for_sigchld) 
    fork() 
    if (child) //do something, return 
    if parent // waitpid(child_pid, NULL,0); print value returned from this waitpid - it is -1 
} 

wdzięczny jeśli ktoś mi pomoże zrozum to.

Odpowiedz

1

Musisz zadzwonić na oczekujące numery, takie jak waitpid lub przyjaciele, np. wait4 itd. W przeciwnym razie możesz mieć zombie processes.

Możesz obsłużyć SIGCHLD, aby otrzymać powiadomienie, że niektóre dziecko się zakończyło (lub zatrzymało się itd.), Ale musisz na to poczekać później.

Obsługa sygnału jest ograniczona do wywoływania małego zestawu funkcji bezpiecznego sygnału asynchronicznego (więcej: patrz: signal(7)). Dobrą radą jest ustawienie wewnątrz flagi volatile sig_atomic_t i przetestowanie jej w późniejszych i bezpieczniejszych miejscach.

18

Naprawdę nie musisz zajmować się SIGCHLD, jeśli masz zamiar uruchomić proces potomny, zrobić kilka rzeczy, a następnie poczekać na zakończenie. W takim przypadku wystarczy zadzwonić pod numer waitpid, gdy będziesz gotowy do synchronizacji. Jedyna rzecz, jaką można uzyskać, to przydatne dla asynchronicznego powiadamiania o zakończeniu dziecka, na przykład, jeśli masz interaktywną (lub długo działającą aplikację demona), która uruchamia różne dzieci i musi się dowiedzieć, kiedy skończy. Jednak SIGCHLD jest również bardzo zły/brzydki w tym celu, ponieważ jeśli używasz kodu biblioteki, który tworzy procesy potomne, możesz przechwycić zdarzenia kończące dzieci w bibliotece i zakłócić ich obsługę. Obsługa sygnałów jest z natury procesem globalnym i zajmuje się stanem globalnym, który zwykle jest Złą rzeczą (tm).

Oto dwa lepsze podejścia do kiedy trzeba procesów potomnych, które będą kończące asynchronicznie:

Approach 1 (select/poll event-based): Upewnij się, że rury do/z każdego procesu potomnego tworzonych . Może to być ich stdin/stdout/stderr lub po prostu fikcyjny manekin. Gdy proces potomny zostanie zakończony, jego koniec potoku zostanie zamknięty, a główna pętla zdarzeń wykryje działanie tego deskryptora pliku. Z tego, że się zamknął, rozpoznajesz, że proces potomny umarł i zadzwoń pod numer waitpid, aby zebrać zombie.

Podejście 2 (zależnie od wątku): Dla każdego utworzonego procesu potomnego należy również utworzyć wątek, który natychmiast wywoła numer waitpid w pidzie procesu podrzędnego. Po pomyślnym powrocie na numer waitpid użyj swoich ulubionych prymitywów synchronizacji wątków, aby reszta programu wiedziała, że ​​dziecko zakończyło pracę lub po prostu zatroszcz się o wszystko, co musisz zrobić w tym wątku kelnera, zanim się zakończy.

Obie metody są modułowe i przyjazne bibliotece (unikają ingerencji w inne części kodu lub biblioteki, które mogą wykorzystywać procesy podrzędne).

+0

Witam, dziękuję za odpowiedź.Ale czego tak naprawdę szukałem, to: Kiedy mam zarówno sig_handler i waitpid w procesie nadrzędnym, sig_handler jest nazywany becaues of sigchld, a następnie drugi waitpid, jak pokazano powyżej w moim Question zwraca -1. Czy mogę po prostu usunąć drugi waitpid, który mam? – Vin

+0

Tak, można tylko z powodzeniem oczekiwać na dany proces potomny tylko jeden raz. Naprawdę błąd to czekać ponownie, ponieważ pid jest "uwolniony" przez pierwsze oczekiwanie i mógł zostać użyty ponownie do nowego procesu potomnego (jeśli zdarzyło Ci się stworzyć inny). –

+0

@R .. Czy moglibyśmy wyjaśnić "Kiedy proces potomny zostanie zakończony, jego koniec rury zostanie nieco zamknięty?" Aby być naprawdę dokładnym, nie byłoby "Kiedy proces potomny zamyka swoją FD, która jest połączona z końcem rury, i nie ma innych procesów mających przyłączenia FD do tego końca rury, wtedy drugi koniec rury będzie sygnalizowane jako zamknięte (otrzymuje EOF) '? Wierzę, że to wyjaśniałoby dokładniej, co się dzieje, a także ważny szczególny przypadek tego, co się dzieje, gdy więcej niż 2 procesy z FD do rury otwarte. – nh2

Powiązane problemy