Próbuję stworzyć demona w Pythonie. Znalazłem następujące pytanie , które zawiera dobre zasoby, które obecnie śledzę, ale jestem ciekaw, dlaczego potrzebny jest podwójny widelec. Przeszukałem google i znalazłem wiele zasobów stwierdzających, że jest to konieczne, ale nie dlaczego.
Niektórzy wspominają, że ma to na celu uniemożliwić demonowi uzyskanie kontrolującego terminala. Jak by to zrobił bez drugiego widelca? Jakie są konsekwencje?
fork()
wywołanie zwraca PID dziecka do rodzica, więc łatwo jest uzyskać PID procesu dziecka, ale nie jest to łatwe uzyskać PID procesu wnuczka ).Odpowiedzi:
Patrząc na kod, do którego odwołuje się pytanie, uzasadnienie jest następujące:
Tak więc ma to na celu zapewnienie, że demon zostanie ponownie przeniesiony na init (na wypadek gdyby proces uruchamiający demona trwał długo) i eliminuje wszelkie szanse na to, że demon odzyska kontrolujący terminal tty. Więc jeśli żaden z tych przypadków nie ma zastosowania, jeden widelec powinien wystarczyć. „ Programowanie sieciowe w systemie Unix - Stevens ” ma dobrą sekcję na ten temat.
źródło
p=fork(); if(p) exit(); setsid()
. W tym przypadku rodzic również wychodzi, a pierwszy proces potomny jest ponownie rodzicem. Magia podwójnego rozwidlenia jest wymagana tylko, aby uniemożliwić demonowi uzyskanie tty.forks
wchild
procesie, to pierwszy proces dziecko będziesession leader
i będzie mógł otworzyć terminal TTY. Ale jeśli ponownie rozwidlę się od tego dziecka i zakończę to pierwsze dziecko, drugie rozwidlone dziecko nie będziesession leader
i nie będzie mogło otworzyć terminala TTY. Czy to stwierdzenie jest poprawne?setsid()
. Tak więc pierwszy rozwidlony proces staje się liderem sesji po wywołaniu,setsid()
a następnie rozwidlamy ponownie, tak że ostatni, podwójnie rozwidlony proces nie jest już liderem sesji. Poza wymogiemsetsid()
bycia liderem sesji, jesteś na miejscu.Próbowałem zrozumieć podwójny widelec i natknąłem się tutaj na to pytanie. Po wielu badaniach doszedłem do tego. Mamy nadzieję, że pomoże to lepiej wyjaśnić sprawę każdemu, kto ma takie samo pytanie.
W Uniksie każdy proces należy do grupy, która z kolei należy do sesji. Oto hierarchia…
Sesja (SID) → Grupa procesów (PGID) → Proces (PID)
Pierwszy proces w grupie procesów staje się liderem grupy procesów, a pierwszy proces w sesji zostaje liderem sesji. Z każdą sesją może być powiązany jeden TTY. Tylko lider sesji może przejąć kontrolę nad TTY. Aby proces był naprawdę zdemonizowany (działał w tle), powinniśmy upewnić się, że lider sesji został zabity, aby sesja nie mogła kiedykolwiek przejąć kontroli nad TTY.
Uruchomiłem przykładowy demon Pythona Sandera Marechala z tej witryny na moim Ubuntu. Oto wyniki z moimi komentarzami.
Zauważ, że proces jest liderem sesji po
Decouple#1
, ponieważ tak jestPID = SID
. Nadal może przejąć kontrolę nad TTY.Zauważ, że
Fork#2
nie jest już liderem sesjiPID != SID
. Ten proces nigdy nie może przejąć kontroli nad TTY. Naprawdę zdemonizowany.Osobiście uważam, że podwójna terminologia jest myląca. Lepszym idiomem może być fork-decouple-fork.
Dodatkowe interesujące linki:
źródło
fork()
już uniemożliwia tworzenie zombie, pod warunkiem, że zamkniesz rodzica.setsid()
przed singlemfork()
? Właściwie myślę, że odpowiedzi na to pytanie odpowiadają na to.Ściśle mówiąc, double-fork nie ma nic wspólnego z wychowywaniem demona jako dziecka
init
. Wszystko, co jest potrzebne do ponownego wychowania dziecka, to to, że rodzic musi wyjść. Można to zrobić za pomocą tylko jednego widelca. Również samo wykonanie podwójnego rozwidlenia nie powoduje ponownego zrobienia procesu demonainit
; rodzic demona musi wyjść. Innymi słowy, rodzic zawsze kończy pracę podczas rozwidlania odpowiedniego demona, aby proces demona był ponownie rodzicielskiinit
.Dlaczego więc podwójny widelec? POSIX.1-2008 Sekcja 11.1.3, " Terminal sterujący ", zawiera odpowiedź (podkreślenie dodane):
To mówi nam, że jeśli proces demona robi coś takiego ...
... wtedy proces demona może zostać przyjęty
/dev/console
jako terminal sterujący, w zależności od tego, czy proces demona jest liderem sesji oraz w zależności od implementacji systemu. Program może zagwarantować, że powyższe wywołanie nie uzyska terminala sterującego, jeśli program najpierw upewni się, że nie jest on liderem sesji.Normalnie, podczas uruchamiania demona,
setsid
jest wywoływana (z procesu potomnego po wywołaniufork
) w celu odłączenia demona od jego kontrolującego terminala. Jednak wywołaniesetsid
oznacza również, że proces wywołujący będzie liderem sesji nowej sesji, co pozostawia otwartą możliwość, że demon mógłby ponownie uzyskać kontrolujący terminal. Technika podwójnego rozwidlenia zapewnia, że proces demona nie jest liderem sesji, co gwarantuje, że wywołanieopen
, jak w powyższym przykładzie, nie spowoduje, że proces demona ponownie przejmie kontrolujący terminal.Technika podwójnego widelca jest nieco paranoiczna. Może to nie być konieczne, jeśli wiesz, że demon nigdy nie otworzy pliku urządzenia terminala. Ponadto w niektórych systemach może nie być konieczne, nawet jeśli demon otwiera plik urządzenia terminala, ponieważ to zachowanie jest zdefiniowane w implementacji. Jednak jedną rzeczą, która nie jest zdefiniowana w ramach implementacji, jest to, że tylko lider sesji może przydzielić terminal sterujący. Jeśli proces nie jest liderem sesji, nie może przydzielić kontrolującego terminala. Dlatego, jeśli chcesz być paranoikiem i być pewnym, że proces demona nie może przypadkowo uzyskać kontrolującego terminala, niezależnie od jakichkolwiek specyfikacji zdefiniowanych w implementacji, niezbędna jest technika podwójnego rozwidlenia.
źródło
LogFile=/dev/console
. Programy nie zawsze mają kontrolę nad tym, które pliki mogą otwierać w czasie kompilacji;)Zaczerpnięte z Bad CTK :
„W niektórych odmianach Uniksa jesteś zmuszony do wykonania podwójnego rozwidlenia podczas uruchamiania, aby przejść do trybu demona. Dzieje się tak, ponieważ pojedyncze rozwidlenie nie jest gwarantowane do odłączenia się od kontrolującego terminala.”
źródło
setsid
po początkowym forku. Następnie zapewnia, że pozostanie odłączony od kontrolującego terminala, ponownie rozwidlając i kończąc sesję lidera (proces, który wywołałsetsid
).fork
że odłącza się od kontrolującego terminala. To jestsetsid
to. Alesetsid
zakończy się niepowodzeniem, jeśli zostanie wezwany przez lidera grupy procesów. Dlategofork
należy wykonać inicjały wcześniej,setsid
aby upewnić się, żesetsid
jest wywoływane z procesu, który nie jest liderem grupy procesów. Drugifork
zapewnia, że końcowy proces (ten, który będzie demonem) nie jest liderem sesji. Tylko liderzy sesji mogą zdobyć terminal kontrolujący, więc ta druga rozwidlenie gwarantuje, że demon nieumyślnie nie przejmie ponownie terminala kontrolującego. Dotyczy to każdego systemu operacyjnego POSIX.Według „Advanced Programming in the Unix Environment” Stephens and Rago, drugi fork jest raczej zaleceniem i ma na celu zagwarantowanie, że demon nie uzyska kontrolującego terminala w systemach opartych na Systemie V.
źródło
Jednym z powodów jest to, że proces nadrzędny może natychmiast wait_pid () dla dziecka, a następnie zapomnieć o tym. Kiedy wnuk umiera, jego rodzic jest inicjowany i będzie czekał () na to - i wyprowadzi go ze stanu zombie.
W rezultacie proces nadrzędny nie musi być świadomy rozwidlonych elementów potomnych, a także umożliwia rozwidlenie długo działających procesów z bibliotek itp.
źródło
Wywołanie daemon () ma wywołanie nadrzędne _exit (), jeśli się powiedzie. Pierwotną motywacją mogło być pozwolenie rodzicowi na wykonanie dodatkowej pracy, podczas gdy dziecko demonizuje.
Może również opierać się na błędnym przekonaniu, że jest to konieczne, aby upewnić się, że demon nie ma procesu nadrzędnego i jest ponownie inicjowany - ale tak się stanie, gdy rodzic umrze w przypadku pojedynczego rozwidlenia.
Przypuszczam więc, że w końcu wszystko sprowadza się do tradycji - pojedynczy widelec wystarczy, o ile i tak rodzic umiera w krótkim czasie.
źródło
Wydaje się, że porządna dyskusja na ten temat znajduje się pod adresem http://www.developerweb.net/forum/showthread.php?t=3025
Cytując mlampkin stamtąd:
źródło
W ten sposób może być łatwiejsze do zrozumienia:
źródło