If waitFor
is not used, killing JVM has no effect on its child process. Here is an example.
Bash script:
#!/usr/bin/env bash
echo "Sleeping..." > 'log'
sleep 30
echo "Wake up" >> 'log'
Java code:
public class Code {
public static void main(String[] args) throws Exception {
Process process = Runtime.getRuntime().exec("./child.sh");
// process.waitFor();
}
}
After Java Code
is issued, JVM terminates immediately. And ps -ef | grep 'child.sh' | grep -v grep
shows:
jing 3535 2761 0 13:47 pts/15 00:00:00 bash ./child.sh
Then after 30 seconds, I check the content of log
file in the current directory. The content is:
Sleeping...
Wake up
And the above grep
command shows nothing now. Now I uncomment process.waitFor()
and recompile Code.java
. After I run java Code
, I use the above grep
command to verify that child.sh
child process is running. Then I issue Ctrl-C
, JVM terminates. Now running the above grep
command shows nothing. And the content of log
file stays as:
Sleeping...
I have checked Process
's Javadoc which does not explain this behavior. Then I use the following code to check the behavior of fork
, execlp
and waitpid
system calls. And it shows the same behavior.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
static void err_sys(const char* msg) {
printf("%s\n", msg);
exit(1);
}
int main(void) {
pid_t pid;
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) {
if (execlp("/home/jing/code/lintcode/child.sh", "child.sh", (char *)0) < 0)
err_sys("execlp error");
}
if (waitpid(pid, NULL, 0) < 0)
err_sys("wait error");
exit(0);
}
I am using Oracle JDK 1.8 on Ubuntu 14.04. uname -a
produces:
Linux jinglin 3.13.0-108-generic #155-Ubuntu SMP Wed Jan 11 16:58:52 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
Can anyone give an explanation about this effect of waitFor
and waitpid
?
Does Process.waitFor() make the process reliant on the java parent? asks a similar problem on MAC platform. But it lacks details. So I ask this question for my environment here.
There's nothing special about waitPid()
, other than the fact that you keep the parent process in the foreground.
If you fork and then wait for the child to finish, you have a (simplified) process tree like this:
─┬= 1 init
└─┬= 2 bash --login
└─┬= 3 java code
└─── 4 bash child.sh
java
is the foreground process in the terminal and the child is in its process group.
When you hit ^C the entire foreground process group gets terminated.1
If you don't wait, then at first your process tree is the same as the one above. The java
process terminates and the child process becomes a child of the process at the root of the process tree.
─┬= 1 init
├──= 2 bash --login
└─── 4 bash child.sh
The child process finishes executing and terminates normally.
1The process group receives a SIGINT, for which the default action is to terminate. However, a different signal handler may be installed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With