We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you a podcast all about Citrix Workspace, moving to the cloud, and analytics & intelligence. Episode 2 coming soon!Listen Now

x

Killing child processes without waiting for the child to finish

Asdf
Asdf asked
on
Medium Priority
768 Views
Last Modified: 2012-06-21
Code is roughly:

open(FILE, "+<file");
flock (FILE,2);
#read data from the file
spawn_child();
#write to the file
close (FILE);

sub REAPER {
   my $wait_pid = wait;
}

sub spawn_child() {
   $SIG{CHLD} = \&REAPER;
   my $pid = fork();
   if (!$pid) {
      exec ("perl script");
      exit; #redundant, I know
   }
   return;
}

The issue is that "script" contains an open to "file", which is currently locked by the parent process. I can't change the order of the main logic (i.e. can't write to the file before I spawn the child). The way it's written now, the parent seems to be waiting for the child to finish executing before it continues on with the logic, creating a deadlock (child is waiting for "file" to be unlocked, parent is waiting for child to finish before unlocking "file"). I need the parent to continue on without the child finishing (the parent also needs to continue to spawn children while the child processes run their course, so waiting for each child to finish is unacceptable).

I've tried running the child as a background process, but this seems to cause "script" to never come out of sleep() commands (/boggle). Any other suggestions?
Comment
Watch Question

Top Expert 2009

Commented:
what are you trying to do?  (high-level)
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015
Commented:
flock (FILE,2);
#read data from the file
flock(FILE,8);
spawn_child();
flock (FILE,2);
#write to the file
close (FILE);

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
Adam314:

Parent spawns X children, running simultaneously. Child and parent communicate through a "status" file. When the child finishes, parent will read that status and spawn a new child.

ozo's solution does solve the file locking deadlock, but the parent still waits for the child to finish executing before moving forward in the logic, meaning I can only have a single child running at once.

What if the child never died on it's own, and it was up to the parent to kill the child when the child set it's status to "done"? As of now, we'd be stuck because the would wait for the child to die indefinitely. How can I make the parent stop waiting for the child to finish, but still reap the child (it's necessary to reap the child because cygwin only allows 256 children from a single process, and I need to exceed this number in my use case)?

Author

Commented:
Another point of interest:

Speckled throughout my code I have various qx!echo "something" >> log.txt!; lines, mostly for debugging purposes. It seems that the parent is "freezing" when it finishes executing the first qx! after the fork(). I'm thinking these qx!'s are the issue, not my method of reaping. I tested this with some basic sample code and saw the same thing:

foreach my $num (1..3) {
   open (T, ">>txt");
   flock (T, 8);
   &spawn();
   flock (T, 2);
   print T "$num parent\n";
   close (T);
}

sub REAPER {
   my $var = ("process died: ",wait);
}

sub spawn {
   $SIG{CHLD} = \&REAPER;
   my $pid = fork();
   if (!$pid) {
      exec ("perl sleeper");
   }
   qx!ls!;
}

the code in sleeper:

sleep(4);
open (T, ">>txt");
flock (T, 2);
print T "sleeper\n";

Resulting "txt":
sleeper
1 parent
sleeper
2 parent
sleeper
3 parent

If you comment out the qx!, the result is:
1 parent
2 parent
3 parent
sleeper
sleeper
sleeper

Is this expected behavior? If so, why, and is there a way around it?
Kelly BlackSenior Linux / DBA / DEVOPS
CERTIFIED EXPERT

Commented:
I believe adding the line

next;

to the parent codeblock where it is to pass over the child should work.
Kelly BlackSenior Linux / DBA / DEVOPS
CERTIFIED EXPERT
Commented:
Also try using this method to trap your errors

To obtain useful error messages, add the following snippet to your script, just beneath the shebang line (the first line of the script; usually !#/usr/local/bin/perl or !#/usr/bin/perl):

BEGIN {
open (STDERR, ">/path/to/somewhere/error.txt");
}

Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.