I wrote two apps to test this... preap and badkids. badkids spawns three zombies and stays alive so they are not reaped by the shell or init. (Technically I think init does the reaping.) badkids should print the PID of the zombie children but does not - so you have to do a ps to get the PIDs. (This would be trivial as it does print its own PID on startup.)
preap looks for a PID parameter on start and passes that to waitpid(). waitpid() currently uses no options but was originally written with WNOHANG. (I think I spelled that right - the docs are in the wait() InfoCenter page.) The status value (passed by reference to waitpid()) is filled with the exit info of the child process. The exit info is encoded to hold more than one piece of info, so I call the WEXITSTATUS() macro to find just the exit value.
But, in short, a program must call a wait() variant *every* time a fork() call is made. This does not mean that it must be called immediately, but it must be called or those process zombies will result. Unix provides multiple different versions of wait() - blocking, non-blocking, wait-for-your-gid, etc... that can be used to reap the children however is best.
As for the code... I do not intend to keep it up forever so I am presenting a "fragmented" URL that will not be indexed. (You have to put the pieces together to grab it.) It will be up for a month or so. (today's date is 4/7/10)
http://www.tablespace.net
/samples/preap-0_1_0.tar.gz
Note on building: will use the AIX supplied make or g(NU)make, but is written for gcc. I have not tried, but see no reason it would not compile on Linux, OS-X, Solaris, etc... (Just tried it on OS-X, it compiled fine.)
This code is free to distribute, re-use, re-post, or line the floor of your home directory. Although, I would make it more robust before re-use - this is just sample, as opposed to production code.