复制进程 fork方法
基本概念
首先看看fork方法的作用:创建一个子进程。调用 fork 函数的进程为父进程,新生成的进程为子进程。
格式为:
pid_t fork(void);
在父进程中返回子进程的 pid,在子进程中返回 0,失败返回-1。
图示:
创建子进程示例
示例1:
#include<stdio.h>
#include<unistd.h>
#include<assert.h>
#include<stdlib.h>
int main(void)
{
char* s = NULL;
int n = 0;
pid_t pid = fork();
assert(pid != -1);
if (pid == 0)
{
s = "child";
n = 3;
}
else
{
s = "parent";
n = 7;
}
for (int i = 0; i < n; ++i)
{
printf("%s\n", s);
sleep(1);
}
exit(0);
}
运行结果:
运行结果说明:复制的子进程相当于把父进程代码复制了一份,而且和父进程是并发运行的,每次运行结果都可能不同。
例如:第二次打印结果和上面的不同。
getpid() 和 getppid()
根据帮助手册可理解:
getpid()是返回这个进程的 ID。
示例:
对于上面的例子,改变for循环里的输出,来看看getpid()作用
for (int i = 0; i < n; ++i)
{
printf("s = %s, pid = %d\n", s, getpid());
sleep(3);
}
运行示例:
getppid()是返回当前进程的父进程的 ID。。。
示例:
for (int i = 0; i < n; ++i)
{
printf("s = %s, pid = %d, ppid = %d\n", s, getpid(), getppid());
sleep(3);
}
运行示例:
可以看出子进程的pid 雀食是父进程的 ID
fork练习
示例:
下面代码会输出几个 A?
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(void)
{
int i = 0;
for (; i < 2; ++i)
{
fork();
printf("A\n");
}
exit(0);
}
运行示例:
分析:
因为每次循环进来都会先复制一份当前程序,所以如果满足for循环条件,会一直复制
僵死进程与处理方法
概念:子进程先于父进程结束,父进程没有调用 wait 获取子进程退出码。
僵死进程示例
代码:
编写一个可以让子进程先结束的程序
#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
int main(void)
{
char* s = NULL;
int n = 0;
pid_t pid = fork();
assert(pid != -1);
if (pid == 0)
{
s = "child";
n = 3;
}
else
{
s = "parent";
n = 6;
}
int i = 0;
for (i; i < n; ++i)
{
printf("s = %s, pid = %d\n", s, getpid());
sleep(3);
}
exit(0);
}
运行结果:
系统把处于这一状态的进程叫做僵死进程 < defunct >。
僵死进程处理方法
父进程使用 wait()方法
介绍:
NAME
wait, waitpid, waitid - wait for process to change state
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
WIFEXITED(wstatus)
returns true if the child terminated normally, that is, by call‐
ing exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(wstatus)
returns the exit status of the child. This consists of the
least significant 8 bits of the status argument that the child
specified in a call to exit(3) or _exit(2) or as the argument
for a return statement in main(). This macro should be employed
only if WIFEXITED returned true.
WIFSIGNALED(wstatus)
returns true if the child process was terminated by a signal.
父进程调用了wait(),就会立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。
程序示例
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main(void)
{
char* s = NULL;
int n = 0;
pid_t pid = fork();
assert(pid != -1);
if (pid == 0)
{
s = "child";
n = 3;
}
else
{
s = "parent";
n = 6;
int val = 0;
int id = wait(&val);
if (WIFEXITED(val))
{
printf("id = %d, val = %d\n", id, WEXITSTATUS(val));
}
}
int i = 0;
for (i; i < n; ++i)
{
printf("s = %s, pid = %d\n", s, getpid());
sleep(3);
}
exit(3);
}
运行结果:
首先是父子进程正常运行
如下图蓝色框所示,当子进程结束时,父进程打印子进程的退出码。
红线表示现在只有父进程在运行,而没有僵死进程了。
end
感谢收看~