tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: using of fork() in multithreaded application
Date: Fri, 24 Jan 2025 10:21:33 +0100
From: Peter Skvarka <ps%softinengines.com@localhost>
Message-ID: <ac714677-bab6-4ac2-b8a1-eafda598636b%softinengines.com@localhost>
| I have this additional info: Forked parent retrieves child output
| through pipe and it waits for child finishing with select() infinitely
| and child stays zombie - I� am seeing flag Z in ps -auxd list.
Since everyone else has been concentrating on other possible issues,
I thought a return to this specific sentence might be useful.
If the child is a zombie, all its file descriptors are now closed.
That would include the pipe to the parent for output to be returned.
The fact that the zombie remains isn't relevant, that's normal (as has
been noted.)
If the parent is actually hanging in select() waiting for a read on
that pipe, then the pipe it is waiting on is not closed. Clearly the
read side isn't (that's what the parent is waiting on) but if the
write side of the pipe has (fully) closed, then the read would return EOF,
and a select() for that should not be hanging. Hence the write side
must still be open.
When a pipe is created, it gets two fds, one for reading, and one for
writing. At this point, it is common for the application to fork() - in
the child one of the two file descriptors gets closed (and in this case, as
the child is now a zombie, we know both of them have eventually been closed),
and in the parent the other one (the direction not desired for its I/O)
should be closed.
A common problem for a parent desiring to read from a pipe from a child
it has created, is for it to fail to close the write side of the pipe after
it has forked the child. In that case, when it attempts to read (or
select/poll/kqueue) from the pipe, it will simply hang, as it is possible
for more data to be sent to the pipe, from the remaining open write side
of the pipe (we know that the parent isn't going to be writing anything
to that file descriptor, but the kernel doesn't).
So, I'd suggest checking to ensure that the write side of the pipe gets
properly closed, after the fork has happened (it can't be before, or the
child would not see the open write side to be able to write to the parent).
The only relevance threading would have to this issue, would be if the
fork() and pipe() were done by different threads, such that the thread
managing the pipe is unaware that the fork() has actually happened (and
hence that there are now two fds - one in each process - able to write to
the pipe).
One other issue to be aware of is that NetBSD does not (yet anyway, one day
I expect we will need to add it) implement "close on fork" for file
descriptors, so if the application happened to be attempting to use that
method to close a file descriptor, that wouldn't work -- but I cannot see
that being relevant here (it affects what fds the child of the fork() sees
as open, which is not the issue that seems to be relevant here - leaving the
read side of the pipe open in a child which will not use it, and which will
exit relatively quickly is generally harmlesss).
kre
ps: all of this assumes that the parent process is actually hanging on
the select() call (either one select sys call waiting forever, or a select
with a timeout constantly timing out and being repeated, perhaps after the
process does some other work) - if it isn't one of those, none of the above
will be useful.
Home |
Main Index |
Thread Index |
Old Index