fork函数
pid_t fork(); 创建一个子进程 返回值:-1 失败 、 等于0表示子进程 、 大于0表示父进程的id
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(); 获取当前进程的id
pid_t getppid(); 获取当前进程的父进程id
uid_t getuid(); 获取当前进程实际用户id
gid_t getgid(); 获取当前进程使用用户组id
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
pid_t pid;
pid = fork();
if (pid == -1 ) {
perror("fork");
exit(1);
} else if (pid > 0) {
while (1) {
printf("I'm parent pid = %d, parentID = %d\n", getpid(), getppid());
sleep(1);
}
} else if (pid == 0) {
while (1) {
printf("child pid = %d, parentID=%d\n", getpid(), getppid());
sleep(1);
}
}
return 0;
}
父子进程共享
读时共享、写时复制。----全局变量
【重点】:父子进程共享:
1. 文件描述符(打开文件的结构体) 2. mmap 建立的映射区(进程间通信详解)
fork之后父进程先执行还是子进程限制性是不确定的。取决于内核所使用的调度算法。
exec函数族
使进程执行某一程序。成功无返回值,失败返回 -1
int execlp(const char *file, const char *arg, ...); 借助 PATH 环境变量找寻待执行程序
参1: 程序名
参2: argv0
参3: argv1
...: argvN
哨兵:NULL
该函数主要用来调用系统程序。如ls,date,cp,cat等
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("========================\n");
pid_t pid = fork();
if (pid == 0) {
execl("/bin/ls", "ls", "-l", "-F", "-a", NULL);
perror("execlp");
exit(1);
} else if (pid > 0) {
sleep(1);
printf("parent\n");
}
return 0;
}
int execl(const char *path, const char *arg, ...); 自己指定待执行程序路径。
加载一个进程,通过 路径+程序名 来加载。
#include <stdio.h>
#include <unistd.h>
int main(void)
{
execl("/bin", "./ls", "-l", "-a", NULL);
return 0;
}
//对比execlp ,如加载 " 命令带有 l F 参数
execlp("ls", "ls", "-l", "-F", NULL); //使用程序名在 PATH 中搜索。
execl("/bin/ls", "ls", "-l", "-F", NULL); //使用参数 1 给出的绝对路径搜索。
孤儿进程
父进程先于子进终止,子进程沦为“孤儿进程”,会被 init 进程领养。
僵尸进程
子进程终止,父进程尚未对子进程进行回收,在此期间,子进程为“僵尸进程”。 kill 对其无效。
wait函数
回收子进程退出资源, 阻塞回收任意一个。
一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但是它的pcb还保留着,内核在其中保留了一些信息。如果正常终止则保存着退出状态,如果异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清楚掉这个进程。
pid_t wait(int *status)
#include <sys/types.h>
#include <sys/wait.h>
参数:(传出) 回收进程的状态。
返回值: 成功: 回收进程的pid
失败: -1, errno
函数作用1: 阻塞等待子进程退出
函数作用2: 清理子进程残留在内核的 pcb 资源
函数作用3: 通过传出参数,得到子进程结束状态
获取子进程正常终止值:
WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。
获取导致子进程异常终止信号:
WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。
waitpid函数: 指定某一个进程进行回收。可以设置非阻塞。
waitpid(-1, &status, 0) == wait(&status);
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: 失败。errno
总结:
wait、waitpid 一次调用,回收一个子进程。
想回收多个用while