一、多进程创建和回收
- 孤儿进程:父进程先退出了,子进程没有退出,成为孤儿进程,父进程变成1号进程。
- 僵尸进程:父进程没有退出,子进程退出了,但是父进程没有回收子进程资源,导致子进程变成僵尸进程。
1. fork()
创建子进程函数,一个进程可以创建多个子进程。
pid_t fork(void)
返回值
小于0 创建失败
等于0 是子进程
大于0 是父进程
示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t ret = fork();
if (ret < 0)
{
perror("fork error");
return -1;
}
else if (ret > 0)
{
printf("here is father,pid is [%d], child pid is [%d]\n", getpid(), ret);
sleep(1);
}
else if (ret == 0)
{
printf("here is child pid is [%d],father is [%d]\n", getpid(), getppid());
}
return 0;
}
2. wait()
父进程回收子进程,其中分为wait()和waitpid()函数
pid_t wait(int *status);
返回值
大于0 返回值为回收的进程id
返回-1 回收失败
参数 status 进程回收状态
可以使用下面的宏来说明当前的回收状态
WIFEXITED(wstatus) 如果正常返回,返回true
WEXITSTATUS(wstatus) 用于输出正常返回的状态 用 %d 格式化输出
WIFSIGNALED(wstatus) 如果被信号杀死,返回true
WTERMSIG(wstatus) 用于输出被哪个信号杀死 用 %d 格式化输出
WIFSTOPPED(wstatus) 如果子进程停止了,返回true
WSTOPSIG(wstatus) 用于输出进程停止是由于哪个信号
WIFCONTINUED(wstatus) 如果进程被信号SIGCONT重启,返回true
WCOREDUMP(wstatus) 如果子进程发生核心转储,返回true
示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// pid_t wait(int *status);
int main()
{
pid_t ret = fork();
if (ret < 0)
{
perror("fork error");
return -1;
}
else if (ret > 0)
{
int waitstatus;
printf("here is father,pid is [%d], child pid is [%d]\n", getpid(), ret);
pid_t waitid = wait(&waitstatus);
if (waitid == -1)
{
perror("wait error");
return -1;
}
else if (waitid > 0)
{
printf("child pid [%d] is over\n", waitid);
}
if (WIFEXITED(waitstatus))
{
printf("exited, status=%d\n", WEXITSTATUS(waitstatus));
}
else if (WIFSIGNALED(waitstatus))
{
printf("killed by signal %d\n", WTERMSIG(waitstatus));
}
else if (WIFSTOPPED(waitstatus))
{
printf("stopped by signal %d\n", WSTOPSIG(waitstatus));
}
else if (WIFCONTINUED(waitstatus))
{
printf("continued\n");
}
}
else if (ret == 0)
{
printf("here is child pid is [%d],father is [%d]\n", getpid(), getppid());
}
return 0;
}
//输出
here is father,pid is [24290], child pid is [24291]
here is child pid is [24291],father is [24290]
child pid [24291] is over
exited, status=0
3. waitpid()
waitpid中的第三个参数可以让回收进程变成非阻塞的。
pid_t waitpid(pid_t pid, int *status, int options);
返回值
大于0 成功,返回的是回收的进程id
等于0 返回0是因为第三个参数设置为了 WNOHANG ,等待是非阻塞的,并且这个时候没有子进程需要被回收
小于0 回收失败
参数 pid 进程id
小于-1 :等待该数字绝对值的所在组所有子进程,例如-21328,则等待21328组内所有子进程
-1 :等待所有子进程
0 :等待组ID等于调用进程的组ID的子进程
大于0 :等待某个子进程
参数 status 进程回收状态
同wait函数的
参数 options 回收选项
0 :不添加选项
WNOHANG :如果没有子进程需要被回收,就立即返回
WUNTRACED :如果一个子进程被停止了,就返回
WCONTINUED :如果一个子进程被SIGCONT从停止转变为运行,就返回
示例:
创建多个子进程并回收它们
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// pid_t waitpid(pid_t pid, int *status, int options);
int main()
{
int i = 0;
for (i = 0; i < 3; i++)
{
pid_t ret = fork();
if (ret < 0)
{
perror("fork error");
return -1;
}
else if (ret > 0)
{
printf("here is father,pid is [%d], child pid is [%d]\n", getpid(), ret);
// pid_t waitid = wait(&waitstatus);
}
else if (ret == 0)
{
sleep(3);
printf("here is child [%d] pid is [%d],father is [%d]\n", i, getpid(), getppid());
break;
}
}
if (i == 3)
{
int waitstatus;
int num = 0;
do
{
pid_t waitid = waitpid(-1, &waitstatus, WNOHANG);
if (waitid == -1)
{
perror("wait error");
return -1;
}
else if (waitid > 0)
{
printf("child pid [%d] is over\n", waitid);
num++;
}
else if (waitid == 0)
{
// 没有进程被回收,可以做其他事情
sleep(1);
continue;
}
if (WIFEXITED(waitstatus))
{
printf("[%d] exited, status=%d\n", waitid, WEXITSTATUS(waitstatus));
}
else if (WIFSIGNALED(waitstatus))
{
printf("[%d] killed by signal %d\n", waitid, WTERMSIG(waitstatus));
}
else if (WIFSTOPPED(waitstatus))
{
printf("[%d] stopped by signal %d\n", waitid, WSTOPSIG(waitstatus));
}
else if (WIFCONTINUED(waitstatus))
{
printf("[%d] continued\n", waitid);
}
if (num == i)
{
break;
}
} while (1);
}
return 0;
}
//输出
here is father,pid is [24553], child pid is [24554]
here is father,pid is [24553], child pid is [24555]
here is father,pid is [24553], child pid is [24556]
here is child [0] pid is [24554],father is [24553]
here is child [2] pid is [24556],father is [24553]
here is child [1] pid is [24555],father is [24553]
child pid [24554] is over
[24554] exited, status=0
child pid [24555] is over
[24555] exited, status=0
child pid [24556] is over
[24556] exited, status=0