I've got a program that is forking to a child to do some work, but I am only doing one child at a time at this time. I am using wait()
to wait for the child to finish, do I need to do anything with SIGCHLD
as well (such as disable the handler)?
In my situation I am getting a value of EINTR
in errno
which leads me to think that I need to mask SIGCHLD
.
In broad strokes, this is the program:
- read arguments
- for(list of work to do)
fork()
- if child,
execlp()
to work program - if parent,
wait()
for child to finish - when child finishes, parent loops to next work item
Theory
POSIX says about
SIG_IGN
(strictly under the XSI extension note):And in the description of
<signal.h>
says that the default signal disposition forSIGCHLD
is'ignore' (code 'I'). However, it is theSIG_IGN
SIG_DFL
behaviour is to 'ignore' the signal; the signal is never generated. This is different from theSIG_IGN
behaviour.So, you don't have to set a signal handler, but you shouldn't get information about the process back — you should just get an error once there are no children left.
Demonstration Code
The
fflush(0);
call ensures standard output (in particular) is flushed, which matters if the output of the sample program is piped to another program.Example Output
The output from the example code agrees with the theory — but requires a little interpretation.
The first section of the output agrees exactly with the theory; the calling code gets no information about the dead children except that there are no dead children (left) to wait for.
The second section of the output agrees with the theory too, but it appears that the children aren't executing before the parent, so the first
wait()
from the parent has no dead children to wait for, and it returns -1. Subsequent calls get the various children, but one escapes unwaited for (but the corpse will be cleaned up by the system). If the code usedwaitpid()
such as:pid_t corpse = waitpid(pid, &status, 0);
, it would wait for each child in turn.Some of this commentary may need revision in the light of the modified comments about 'ignore' above. TBD — out of time right now.
Mac OS X 10.8.4 on 3 GHz Intel Core 2 Duo, GCC 4.6.0, 64-bit compilation:
This was a quick adaptation of some existing code to test the behaviour of
SIGINT
andpause()
. It may have some superfluous material in it. You do not have to callwait()
or one of its relatives in the signal handler; you may do so if you wish, though.If you do not care about the exit status of forked children, then you can ignore
SIGCHLD
.If you do care about the exit status, you can install a signal handler, and perform a
waitpid()
call within the signal handler to reap the exit status values from the exited child processes. This call should be in a loop, until there are not more exited children. You would use-1
in the first parameter, andWNOHANG
in the last parameter to wait for any child in a non-blocking way. Ifwaitpid()
returns 0, it means the call succeeded, but there are no more children to wait on.