Na swojej stronie internetowej o tej sztuczki self-pipe , Dan Bernstein wyjaśnia warunek wyścigu select()
i sygnałów, oferuje obejście i stwierdza, że
Oczywiście właściwą rzeczą byłoby
fork()
zwrócenie deskryptora pliku, a nie identyfikatora procesu.
Co on przez to rozumie - czy jest to coś w tym, że select()
w procesach potomnych można radzić sobie ze zmianami stanu zamiast korzystać z procedury obsługi sygnałów, aby otrzymywać powiadomienia o tych zmianach stanu?
signals
file-descriptors
fork
Lassi
źródło
źródło
signalfd
czy wtedy coś takiego było?wait()
, były rzeczy, których nie można było zrobić, więc ktoś wymyślił SIGCHLD, ale to była zła robota. Z mojego doświadczenia, a teraz, że one istnieją, zraszanie ładne, powodują blokowaniawait3()
,wait4()
i / lubwaitpid()
połączeń w kluczowych miejscach (chyba głównym pętla zdarzenie) jest znacznie lepsza alternatywa.Odpowiedzi:
Problem jest opisany w twoim źródle,
select()
powinien być przerwany przez sygnały takie jakSIGCHLD
, ale w niektórych przypadkach nie działa tak dobrze. Obejściem tego problemu jest zapis sygnału na potoku, który jest następnie obserwowanyselect()
. Po to jest oglądanie deskryptorów plikówselect()
, aby obejść problem.Obejście to zasadniczo zamienia zdarzenie sygnalizacyjne w zdarzenie deskryptora pliku. Gdyby
fork()
po prostu zwrócił fd w pierwszej kolejności, obejście nie byłoby wymagane, ponieważ fd można by prawdopodobnie użyć bezpośrednio z nimselect()
.Więc tak, twój opis w ostatnim akapicie wydaje mi się odpowiedni.
Innym powodem, dla którego fd (lub inny rodzaj uchwytu jądra) byłby lepszy niż zwykły numer identyfikacyjny procesu, jest to, że PID mogą zostać ponownie wykorzystane po śmierci procesu. Może to stanowić problem w niektórych przypadkach podczas wysyłania sygnałów do procesów, może nie być pewne, że proces jest tym, o którym myślisz, że nie, a nie innym, który ponownie wykorzystuje ten sam PID. (Chociaż myślę, że nie powinno to stanowić problemu przy wysyłaniu sygnałów do procesu potomnego, ponieważ rodzic musi uruchomić
wait()
dziecko, aby jego identyfikator PID został zwolniony).źródło
wait()
.clone
, który jest rzeczywistym wywołaniem systemowym wywoływanym przez fork na LInux. Flaga umożliwiająca to nazywa sięCLONE_PIDFD
- patrz na przykład lwn.net/Articles/784831 .To tylko rozmyślanie w stylu „byłoby świetnie, gdyby Unix był zaprojektowany inaczej niż jest”.
Problem z PID polega na tym, że żyją w globalnej przestrzeni nazw, w której mogą być ponownie wykorzystane do innego procesu, i byłoby miło, gdyby
fork()
zwrócono rodzicowi jakiś uchwyt, który gwarantowałby, że zawsze będzie odnosił się do procesu potomnego, i że może przejść do innych procesów przez dziedziczenie lub gniazda unix /SCM_RIGHTS
[1].Zapoznaj się również z dyskusją tutaj dotyczącą niedawnego wysiłku „naprawienia” tego w Linuksie, w tym dodanie flagi, do
clone()
której spowoduje, że zwróci pid-fd zamiast PID.Ale nawet wtedy nie wyeliminowałoby to potrzeby takiego hakowania [2] lub lepszych interfejsów, ponieważ sygnały powiadamiające proces nadrzędny o stanie dziecka nie są jedynymi, które chciałbyś obsłużyć w głównej pętli programu. Niestety, rzeczy takie jak
epoll(7) + signalfd(2)
Linux czykqueue(2)
BSD nie są standardowe - jedyny standardowy interfejs (ale nie obsługiwany w starszych systemach) jest znacznie gorszypselect(2)
.[1] Zapobieganie ponownemu cyklowi PID do czasu
waitpid()
zwrócenia wywołania syscall i wykorzystania jego wartości zwracanej można prawdopodobnie osiągnąć w nowszych systemach, używającwaitid(.., WNOWAIT)
zamiast tego.[2] Nie komentowałbym twierdzenia DJ Bernsteina, że to on wymyślił (przepraszam za apofazę ;-)).
źródło
Bernstein nie podaje zbyt dużego kontekstu dla tej uwagi „Right Thing”, ale zaryzykuję zgadnięcie: powrót rozwidlenia (2) PID jest niezgodny z zwracaniem deskryptorów plików przez open (2), creat (2) itp. Reszta systemu uniksowego mogła manipulować procesem za pomocą deskryptora pliku reprezentującego proces, zamiast PID. Istnieje systemowy sygnał wywołania signalfd (2) , który pozwala na nieco lepszą interakcję między sygnałami i deskryptorami plików i pokazuje, że proces reprezentujący deskryptor pliku reprezentujący proces może zadziałać.
źródło
pidfd_open
również Linuksa, patrz na przykład lwn.net/Articles/789023