Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, Any help will be much appreciated on the subject. I am writing an application whereby I would like to fork a few processes, and in these forked processes, fork additionnal processes without any of the parent processes to have to wait for their children to finish.
It is something of the form:
foreach $customer (@customers) { if ($cust_pid = fork) { #in parent sleep 1; $SIG{CHLD} = 'IGNORE'; } if ($cust_pid == 0) { #in child foreach $router (@routers) { if ($router_pid = fork) { #in parent sleep 1; $SIG{CHLD} = 'IGNORE'; } if ($router_pid == 0) { #in child #do something exit; #this exits child process at router level } } } exit; #this exits child process at customer level }

So basically, what I am trying to do is for each customer in my list of customers, fork a process, and then for each router owned by that customer, fork another process and this is where my main application takes place, at router level. I think what I have here are nested forks. My probelm is that my application is giving me really strange results when I have nested forks. Perl seems to be confusing which child belongs to which parent or something of the kind. The reason I am saying this is because when I test my code without the forking at customer level, just at router level, it works perfectly. More over, when I replace $SIG{CHLD} = 'IGNORE'; with waitpid($cust_pid, 0); at the customer level forking (ie make the parent process wait for its child process to terminate before beginning a new one), the code works perfectly as well. I need though to have all these processes run concurrently and hence I do not want to use the waitpid($cust_pid, 0); solution. Any help on possible alternative ways will be VERY appreciated.

Thanks in advance,
Elias.

PS: if you're interested by what kind of application I am writing, it's basically a polling engine that monitors some remote site routers via an ISDN link, and the polls are made from central site routers via the cisco ping mib. In order to do the polling, I am using Net::SNMP module. Just thought you might want to know.

Replies are listed 'Best First'.
Re: Nested forks -help!
by ariels (Curate) on Jul 23, 2001 at 18:06 UTC
    The code you posted runs exit ("this exits child process at customer level") in both child and parent on the outer loop! If you don't ignore SIGCHLD but instead wait for the child to finish, it "works", as long as @customers <= 1. But are you sure it ever starts a second "customers" process with this code? It would appear to spawn (at most) one, then terminate.

    Other than that, what exactly happens when you say "Perl seems to be confusing which child belongs to which parent or something of the kind"? None of your parents seem to take any heed of their children!

      you're right, the exit call at customer level is wrong, it should be at the end of the
      if ($cust_pid == 0) {
      }
      section. And this is where it is in my application. Sorry for not spotting the typo in my message before submitting it.
      I need multiple customers running at the same time so I can't wait for the child to finish unfortunately.

      What I mean by "Perl seems to be confusing...." is that the Net::SNMP module starts giving me strange errors in the form of "No response from Agent on router" and "Sent pid is not the same as the one received", whereas when I omit forking at customer level, I do not get any errors at all.

      I read somewhere that SIGCHLD is not very reliable with Perl and that race conditions could occur. Can it be just that the source of my problem?

        Unfortunately I'm unfamiliar with the Net::SNMP module and the SNMP protocol, so I shan't be able to help much.

        I read somewhere that SIGCHLD is not very reliable with Perl and that race conditions could occur. Can it be just that the source of my problem?
        Not if $SIG{CHLD} is indeed set to 'IGNORE' in your program.

        One possibility for getting into troubl with multiple processes is to try to use them same socket with all of them. This will probably happen if you create your Net::SNMP session in advance for all your children and try to use it from all of them; either create a separate object in each (leaf!) child or put all uses of the session inside mutexes.

Re: Nested forks -help!
by Malkavian (Friar) on Jul 23, 2001 at 19:08 UTC
    For a nice simple way to take care of your forks, and most of the problems assocated, unless you absolutely have to write them yourself/are so familiar with them that you don't get caught by the many gotchas that happen, try using Proc::Simple from CPAN.
    This will let you concentrate more on the functionality of the code than the workings of the fork.

    Malk