fork函数
pid_t fork(void)创建子进程。父子进程各自返回。父进程返回子进程pid。 子进程返回 0。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
printf("Begin... ");
pid_t pid = fork();
if (pid < 0)
{
perror("fork err");
exit(1);
}
else if (pid == 0)
{//子进程
printf("I am a child pid, pid = %d, ppid = %d ", getpid(), getppid());
}
else if (pid > 0)
{//父进程
printf("I am a parent pid, childpid = %d, self = %d, ppid = %d ", pid, getpid(), getppid());
sleep(1);
}
printf("End...\n");
return 0;
}
创建N个子进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int n = 5;
int i = 0;
pid_t pid = 0;
for (; i < 5; ++i) {
pid = fork();
if (pid == 0) {
//son
break;
}
}
sleep(i);
if (i < 5) {
printf("I am child , pid = %d, ppid = %d\n", getpid(), getppid());
} else {
printf("I am father , pid = %d, ppid = %d\n", getpid(), getppid());
}
return 0;
}
父子进程:读时共享,写时复制。
#include <stdio.h>
#include <unistd.h>
int var = 100;
int main(int argc, char const *argv[])
{
pid_t pid = fork();
if (pid == 0) {
//son
sleep(5);
printf("var = %d, child, pid = %d, ppid = %d\n", var, getpid(), getppid());
var = 1001;
printf("var = %d, child, pid = %d, ppid = %d\n", var, getpid(), getppid());
} else if (pid > 0) {
//parent
//sleep(5); //确保子进程修改成功
var = 1020;
printf("var = %d, parent, pid = %d, ppid = %d\n", var, getpid(), getppid());
}
return 0;
}
孤儿进程和僵尸进程
孤儿进程:父进程先于子进终止,子进程沦为“孤儿进程”,会被 init 进程领养。
僵尸进程:子进程终止,父进程尚未对子进程进行回收,在此期间,子进程为“僵尸进程”。 kill 对其无效。这里要注意,每个进程结束后都必然会经历僵尸态,时间长短的差别而已。
子进程终止时,子进程残留资源PCB存放于内核中,PCB记录了进程结束原因,进程回收就是回收PCB。回收僵尸进程,得kill它的父进程,让孤儿院去回收它。
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
pid_t pid = fork();
if (pid == 0) {
while(1) {
printf("I am child, pid = %d, ppid = %d\n", getpid(), getppid());
}
} else if (pid > 0) {
printf("I am child, pid = %d, ppid = %d\n", getpid(), getppid());
sleep(5);
printf("I am parent, I will die\n");
}
return 0;
}
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
pid_t pid = fork();
if (pid == 0) {
printf("I am child, pid = %d, ppid = %d\n", getpid(), getppid());
sleep(2);
printf("I am a child, I will die\n");
} else if (pid > 0) {
while(1) {
printf("I am father, pid = %d, ppid = %d\n", getpid(), getppid());
}
}
return 0;
}
wait函数
pid_t wait(int *status)
参数:(传出) 回收进程的状态。
返回值:成功: 回收进程的pid;失败: -1, errno。
函数作用:1. 阻塞等待子进程退出函数作用;2. 清理子进程残留在内核的 pcb 资源;3. 通过传出参数,得到子进程结束状态。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
pid_t pid = fork();
if (pid == 0) {
printf("I am child, pid = %d, will die!\n", getpid());
//sleep(102);
exit(100);
} else if (pid > 0) {
printf("I am parent, wait for child die!\n");
int status;
pid_t wpid = wait(&status);
printf("wait ok, wpid = %d, pid = %d\n", wpid, pid);
if (WIFEXITED(status)) {
printf("child exit with %d\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("child killed by %d\n", WTERMSIG(status));
}
while (1) {
sleep(1);
}
}
return 0;
}
waitpid函数
指定某一个进程进行回收。可以设置非阻塞。
pid_t waitpid(pid_t pid, int *status, int options)
参数:pid:指定回收某一个子进程pid。> 0: 待回收的子进程pid;-1:任意子进程;0:同组的子进程。
status:(传出) 回收进程的状态。
options:WNOHANG 指定回收方式为,非阻塞。
返回值:> 0 : 表成功回收的子进程 pid;0 : 函数调用时, 参3 指定了WNOHANG, 并且,没有子进程结束。-1: 失败。
一次wait/waitpid函数调用,只能回收一个子进程。上一个例子,父进程产生了5个子进程,wait会随机回
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
int i = 0;
pid_t pid = -1;
for (; i < 5; ++i)
{
pid = fork();
if (pid == 0)
{
break;
}
}
if (i < 5)
{
sleep(i);
printf("I am a child, pid = %d\n", getpid());
}
if (i == 5)
{
printf("I am parent!\n");
//-1代表子进程都死了,都收了
while (1) {
pid_t wpid = waitpid(-1, NULL, WNOHANG);
if (wpid == -1)
{
perror("waitpid error");
break;
}
else if (wpid > 0)
{
printf("waitpid = %d\n", wpid);
}
}
}
return 0;
}