📅  最后修改于: 2021-01-18 06:33:42             🧑  作者: Mango
如我们所见,每当我们使用fork从程序创建子进程时,都会发生以下情况-
如果父进程比子进程早完成任务然后退出或退出,会发生什么?现在谁将成为子进程的父进程?子进程的父进程是init进程,它是启动所有任务的第一个进程。
要监视子进程的执行状态,检查子进程是正在运行还是已停止或检查执行状态等。使用wait()系统调用及其变体。
让我们考虑一个示例程序,其中父进程不等待子进程,这导致init进程成为子进程的新父进程。
#include
int main() {
int pid;
pid = fork();
// Child process
if (pid == 0) {
system("ps -ef");
sleep(10);
system("ps -ef");
} else {
sleep(3);
}
return 0;
}
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jan20 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 Jan20 ? 00:04:41 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
3108506 5445 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 5446 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 21894 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 21895 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 27309 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
3108506 27311 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
8295652 32407 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
4688328 49830 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
3108506 50854 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
4688328 64936 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
3108506 64937 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
4688328 67563 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
5942779 68128 0 0 Jan22 ? 00:00:07 /sbin/klogd -c 1 -x -x
3108506 68238 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
4688328 68999 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
3108506 69212 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 74090 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
3108506 74091 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
4688328 74298 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 74299 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
6327201 74901 0 0 Jan20 ? 00:00:38 /sbin/klogd -c 1 -x -x
6327201 77274 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 78621 0 0 Jan20 ? 00:00:33 /sbin/klogd -c 1 -x -x
7528790 80536 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ]
6327201 80542 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ]
4688328 82050 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ]
3108506 82051 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ]
7528790 84116 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 84136 0 19 Jan20 ? 21:13:38 /sbin/klogd -c 1 -x -x
7528790 84140 0 0 Jan20 ? 00:00:28 /sbin/klogd -c 1 -x -x
3108506 84395 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
4688328 84396 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
5942779 84397 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
3108506 84928 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
4688328 84929 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
5942779 84930 0 0 Jan22 ? 00:00:30 [/sbin/klogd -c ]
7528790 84970 0 0 Jan20 ? 00:00:34 /sbin/klogd -c 1 -x -x
3108506 85787 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 85789 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 86368 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 86402 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 87027 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
7528790 87629 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
7528790 87719 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
4688328 88138 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 88140 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 89353 0 99 Jan22 ? 2-07:35:14 /sbin/klogd -c 1 -x -x
5942779 91836 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
4688328 125358 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 125359 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 127456 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 127457 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
8023807 163891 0 0 05:41 ? 00:00:00 main
8023807 164130 0 0 05:41 ? 00:00:00 sh -c cd /home/cg/root/8023807; timeout 10s main
8023807 164136 164130 0 05:41 ? 00:00:00 timeout 10s main
8023807 164137 164136 0 05:41 ? 00:00:00 main
8023807 164138 164137 0 05:41 ? 00:00:00 main
8023807 164139 164138 0 05:41 ? 00:00:00 ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jan20 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 Jan20 ? 00:04:41 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
3108506 5445 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 5446 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 21894 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 21895 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 27309 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
3108506 27311 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
8295652 32407 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
4688328 49830 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
3108506 50854 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
4688328 64936 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
3108506 64937 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
4688328 67563 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
5942779 68128 0 0 Jan22 ? 00:00:07 /sbin/klogd -c 1 -x -x
3108506 68238 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
4688328 68999 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
3108506 69212 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 74090 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
3108506 74091 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
4688328 74298 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 74299 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
6327201 74901 0 0 Jan20 ? 00:00:38 /sbin/klogd -c 1 -x -x
6327201 77274 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 78621 0 0 Jan20 ? 00:00:33 /sbin/klogd -c 1 -x -x
7528790 80536 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ]
6327201 80542 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ]
4688328 82050 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ]
3108506 82051 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ]
7528790 84116 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 84136 0 19 Jan20 ? 21:13:48 /sbin/klogd -c 1 -x -x
7528790 84140 0 0 Jan20 ? 00:00:28 /sbin/klogd -c 1 -x -x
3108506 84395 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
4688328 84396 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
5942779 84397 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
3108506 84928 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
4688328 84929 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
5942779 84930 0 0 Jan22 ? 00:00:30 [/sbin/klogd -c ]
7528790 84970 0 0 Jan20 ? 00:00:34 /sbin/klogd -c 1 -x -x
3108506 85787 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 85789 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 86368 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 86402 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 87027 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
7528790 87629 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
7528790 87719 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
4688328 88138 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 88140 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 89353 0 99 Jan22 ? 2-07:35:24 /sbin/klogd -c 1 -x -x
5942779 91836 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
4688328 125358 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 125359 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 127456 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 127457 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
8023807 164138 0 0 05:41 ? 00:00:00 main
8023807 164897 164138 0 05:41 ? 00:00:00 ps -ef
注–请注意,父进程PID为94,子进程PID为95。退出父进程后,子进程的PPID从94更改为1(初始化进程)。
以下是监视子进程的系统调用的变体-
如下所述, wait()系统调用将等待子级之一终止并在缓冲区中返回其终止状态。
#include
#include
pid_t wait(int *status);
此调用成功返回终止子进程的进程ID,失败返回-1。 wait()系统调用暂停当前进程的执行,并无限期等待,直到其子进程之一终止。子项的终止状态在状态中可用。
让我们修改前面的程序,以便父进程现在等待子进程。
#include
int main() {
int pid;
int status;
pid = fork();
// Child process
if (pid == 0) {
system("ps -ef");
sleep(10);
system("ps -ef");
return 3; //exit status is 3 from child process
} else {
sleep(3);
wait(&status);
printf("In parent process: exit status from child is decimal %d, hexa %0x\n", status, status);
}
return 0;
}
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jan20 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 Jan20 ? 00:04:42 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
3108506 5445 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 5446 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 21894 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 21895 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 27309 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
3108506 27311 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
8295652 32407 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
4688328 49830 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
3108506 50854 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
4688328 64936 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
3108506 64937 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
4688328 67563 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
5942779 68128 0 0 Jan22 ? 00:00:07 /sbin/klogd -c 1 -x -x
3108506 68238 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ]
4688328 68999 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
3108506 69212 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 74090 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
3108506 74091 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
4688328 74298 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 74299 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
6327201 74901 0 0 Jan20 ? 00:00:38 /sbin/klogd -c 1 -x -x
6327201 77274 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 78621 0 0 Jan20 ? 00:00:33 /sbin/klogd -c 1 -x -x
7528790 80536 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ]
6327201 80542 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ]
4688328 82050 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ]
3108506 82051 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ]
7528790 84116 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 84136 0 19 Jan20 ? 21:19:39 /sbin/klogd -c 1 -x -x
7528790 84140 0 0 Jan20 ? 00:00:28 /sbin/klogd -c 1 -x -x
3108506 84395 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
4688328 84396 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
5942779 84397 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
3108506 84928 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
4688328 84929 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ]
5942779 84930 0 0 Jan22 ? 00:00:30 [/sbin/klogd -c ]
7528790 84970 0 0 Jan20 ? 00:00:34 /sbin/klogd -c 1 -x -x
3108506 85787 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 85789 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 86368 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 86402 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 87027 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
7528790 87629 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
7528790 87719 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
4688328 88138 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
4688328 88140 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ]
5942779 89353 0 99 Jan22 ? 2-07:41:15 /sbin/klogd -c 1 -x -x
5942779 91836 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ]
4688328 125358 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 125359 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
4688328 127456 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
3108506 127457 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ]
8023807 191762 0 0 05:47 ? 00:00:00 sh -c cd /home/cg/root/8023807; timeout 10s main
8023807 191768 191762 0 05:47 ? 00:00:00 timeout 10s main
8023807 191769 191768 0 05:47 ? 00:00:00 main
8023807 191770 191769 0 05:47 ? 00:00:00 main
8023807 192193 0 0 05:47 ? 00:00:00 sh -c cd /home/cg/root/8023807; timeout 10s main
8023807 192199 192193 0 05:47 ? 00:00:00 timeout 10s main
8023807 192200 192199 0 05:47 ? 00:00:00 main
8023807 192201 192200 0 05:47 ? 00:00:00 main
8023807 192202 192201 0 05:47 ? 00:00:00 ps -ef
注–即使子级返回退出状态3,但为什么父进程将其视为768。状态存储在高位字节中,因此它以十六进制格式存储为0X0300,即十进制768。正常终止如下
Higher Order Byte (Bits 8 to 15) | Lower Order Byte (Bits 0 to 7) |
Exit status (0 to 255) | 0 |
wait()系统调用具有局限性,例如它只能等到下一个子项的退出。如果我们需要等待特定的孩子,则不能使用wait(),但是可以使用waitpid()系统调用。
waitpid()系统调用将等待指定的子项终止,并在缓冲区中返回其终止状态,如下所述。
#include
#include
pid_t waitpid(pid_t pid, int *status, int options);
上面的调用在成功时返回终止子进程的进程ID,在失败时返回-1。 waitpid()系统调用暂停当前进程的执行,并无限期等待,直到指定的子项(按pid值)终止为止。子项的终止状态在状态中可用。
pid的值可以是以下任一个-
<-1-等待任何子进程的进程组ID等于pid的绝对值。
-1-等待任何子进程,这等于wait()系统调用的子进程。
0-等待任何子进程的进程组ID与调用进程的ID相等。
> 0-等待任何子进程的ID等于pid的值。
默认情况下,waitpid()系统调用仅等待终止的子级,但是可以使用options参数修改此默认行为。
现在,让我们以一个程序为例,等待具有其进程ID的特定进程。
#include
#include
#include
#include
int main() {
int pid;
int pids[3];
int status;
int numprocesses = 0;
int total_processes = 3;
while (numprocesses < total_processes) {
pid = fork();
// Child process
if (pid == 0) {
printf("In child process: process id is %d\n", getpid());
sleep(5);
return 4;
} else {
pids[numprocesses] = pid;
numprocesses++;
printf("In parent process: created process number: %d\n", pid);
}
}
// Waiting for 3rd child process
waitpid(pids[total_processes - 1], &status, 0);
if (WIFEXITED(status) != 0) {
printf("process %d exited normally\n", pids[total_processes - 1]);
printf("exit status from child is %d\n", WEXITSTATUS(status));
} else {
printf("process %d not exited normally\n", pids[total_processes - 1]);
}
return 0;
}
编译并执行后,输出如下。
In child process: process id is 32528
In parent process: created process number: 32528
In child process: process id is 32529
In parent process: created process number: 32528
In parent process: created process number: 32529
In child process: process id is 32530
In parent process: created process number: 32528
In parent process: created process number: 32529
In parent process: created process number: 32530
process 32530 exited normally
exit status from child is 4
现在,让我们检查waitid()系统调用。该系统调用等待子进程更改状态。
#include
int waitpid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
上面的系统调用等待子进程更改状态,此调用将挂起当前/调用进程,直到其任何子进程更改其状态为止。参数“ infop”用于记录孩子的当前状态。如果进程已更改其状态,则此调用将立即返回。
idtype的值可以是以下任一个-
P_PID-等待任何子进程的ID等于ID。
P_PGID-等待任何子进程,其进程组ID等于ID。
P_ALL-等待任何子进程,并且id被忽略。
options参数用于指定要更改的状态,并且可以通过带有下述标志的按位或运算来形成状态-
WCONTINUED-返回已停止并已继续的任何子代的状态。
WEXITED-等待进程退出。
WNOHANG-立即返回。
WSTOPPED-收到信号后等待已停止的所有孩子的进程并返回状态。
如果由于其子项之一的状态更改而返回并且使用WNOHANG,则此调用返回0。如果出现错误,它将返回–1,并设置适当的错误编号。
#include
#include
#include
#include
int main() {
int pid;
int pids[3];
int status;
int numprocesses = 0;
int total_processes = 3;
siginfo_t siginfo;
while (numprocesses < total_processes) {
pid = fork();
// Child process
if (pid == 0) {
printf("In child process: process id is %d\n", getpid());
sleep(5);
return 2;
} else {
pids[numprocesses] = pid;
numprocesses++;
printf("In parent process: created process number: %d\n", pid);
}
}
// Waiting for 3rd child process
status = waitid(P_PID, pids[total_processes - 1], &siginfo, WEXITED);
if (status == -1) {
perror("waitid error");
return 1;
}
printf("Info received from waitid is: ");
printf("PID of child: %d, real user id of child: %d\n", siginfo.si_pid, siginfo.si_uid);
return 0;
}
执行并编译上述程序后,结果如下。
In child process: process id is 35390
In parent process: created process number: 35390
In child process: process id is 35391
In parent process: created process number: 35390
In parent process: created process number: 35391
In child process: process id is 35392
In parent process: created process number: 35390
In parent process: created process number: 35391
In parent process: created process number: 35392
Info received from waitid is: PID of child: 35392, real user id of child: 4581875