程序demo
#include <sys/types.h> #include <unistd.h> pid_t fork(void); // 创建一个子进程 pid_t getpid(void); // 获取当前进程的id pid_t getppid(void); // 获取当前进程父进程的id
fork函数返回值:
失败 返回 -1
成功 两次返回
父进程返回子进程的 pid_t
子进程返回 0
创建一个子进程的程序:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { printf("Begin ..\n"); pid_t pid = fork(); if (pid < 0) { perror("fork err\n"); exit(1); } if (pid == 0) { printf("I am a Child, pid = %d, ppid = %d \n", getpid(), getppid()); } else if (pid > 0) { printf("I am a Parent, childpid = %d, selfpid = %d, ppid = %d \n", pid, getpid(), getppid()); sleep(1); // 如果不加sleep,父进程先消亡,此时子线程会变成孤儿线程 } printf("End ...\n"); return 0; }
输出结果
Begin .. I am a Parent, childpid = 73714, selfpid = 73713, ppid = 73479 I am a Child, pid = 73714, ppid = 73713 End ... End ...
为什么会执行两次printf(“End …\n”)函数呢?
在fork函数生成子进程之后,父进程和子进程都会执行fork语句之后的代码。
补充:linux查看进程信息的命令
查看进程信息:ps aux
查看进程组信息:ps ajx
给进程发送一个信号:kill
杀死一个进程:kill -9 pid
创建多个子进程的程序:
int main() { printf("Begin ..\n"); for (int i = 0; i < 5; i++) { pid_t pid = fork(); if (pid < 0) { perror("fork err\n"); exit(1); } if (pid == 0) { printf("I am a Child, pid = %d, ppid = %d \n", getpid(), getppid()); break; // 子进程退出for循环 } else if (pid > 0) { printf("I am a Parent, childpid = %d, selfpid = %d, ppid = %d \n", pid, getpid(), getppid()); sleep(1); } } printf("End ...\n"); return 0; }
执行结果:
Begin .. I am a Parent, childpid = 74179, selfpid = 74178, ppid = 73479 I am a Child, pid = 74179, ppid = 74178 End ... I am a Parent, childpid = 74182, selfpid = 74178, ppid = 73479 I am a Child, pid = 74182, ppid = 74178 End ... I am a Parent, childpid = 74192, selfpid = 74178, ppid = 73479 I am a Child, pid = 74192, ppid = 74178 End ... I am a Parent, childpid = 74202, selfpid = 74178, ppid = 73479 I am a Child, pid = 74202, ppid = 74178 End ... I am a Parent, childpid = 74203, selfpid = 74178, ppid = 73479 I am a Child, pid = 74203, ppid = 74178 End ... End ...
如果子进程不及时退出for循环,子进程也会生成子进程,程序执行完不单单是生成5个子进程了。
物理内存共享模式:读时共享,写时复制。
进程共享验证程序
int main() { printf("Begin ..\n"); int var = 100; pid_t pid = fork(); if (pid == 0) { printf("I am a Child, var = %d, pid = %d, ppid = %d \n", var, getpid(), getppid()); var = 0; // 子进程修改 var 变量的值 printf("I am a Child, var = %d, pid = %d, ppid = %d \n", var, getpid(), getppid()); } else if (pid > 0) { sleep(3); printf("I am a Parent, var = %d, childpid = %d, selfpid = %d, \ ppid = %d \n", var, pid, getpid(), getppid()); } printf("End ...\n"); return 0; }
输出结果:
Begin .. I am a Child, var = 100, pid = 74447, ppid = 74446 I am a Child, var = 0, pid = 74447, ppid = 74446 End ... I am a Parent, var = 100, childpid = 74447, selfpid = 74446, ppid = 73479 End ...
execl函数的作用:
fork创建子进程后执行和父进程相同的程序,子进程可以调用execl函数执行另一个程序。当一个进程调用execl函数时,该进程的用户空间代码和数据完成被新程序替换,从新程序的启动例程开始执行。
常用的execl函数
int execl(const char *path, const char *arg, .../* (char *) NULL */); int execlp(const char *file, const char *arg, .../* (char *) NULL */);
execl 执行其它程序
execlp 执行其它程序时,使用PATH变量,执行的程序可以不用加路径
file 要执行的程序
arg 参数列表,最后一个参数以NULL结尾
返回值,只有失败才返回
程序demo
int main() { //execl("/bin/ls", "ls", "-l", "--color=auto", NULL); execlp("ls", "ls", "-l", "--color=auto", NULL); perror("exec err"); return 0; }
注:第二个 “ls” 是一个无用的参数占位符
孤儿进程:父进程死了,子进程被init进程领养
僵尸进程:子进程死了,父进程没有回收子进程的资源(PCB)
如何回收僵尸进程:杀死父进程
孤儿进程demo
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { printf("Begin ..\n"); pid_t pid = fork(); if (pid < 0) { perror("fork err\n"); exit(1); } if (pid == 0) { printf("I am a Child, pid = %d, ppid = %d \n", getpid(), getppid()); sleep(5); } else if (pid > 0) { printf("I am a Parent, childpid = %d, selfpid = %d, ppid = %d \n", pid, getpid(), getppid()); } printf("End ...\n"); return 0; }
输出结果
Begin .. I am a Parent, childpid = 74966, selfpid = 74965, ppid = 73479 End ... [zhpng@iZuf6ddpzz3ipktm5kj01cZ webserver]$ I am a Child, pid = 74966, ppid = 1 End ...
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *wstatus, int options);
wait函数回收子进程,查看子进程的死亡原因。
作用
阻塞等待
回收子进程资源
查看子进程死亡原因
pid_t wait(int *status)
status 出参,死亡原因
返回值
成功 返回终止的子进程ID
失败 返回 -1
子进程死亡原因
正常死亡:WIFEXITED,如果WIFEXITED为真,使用WEXITSTATUS得到退出状态
非正常死亡:WIFSIGNALED,如果WIFSIGNALED为真,使用WEXITSTATUS得到信号
wait函数回收多个子进程demo
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> int main() { printf("Begin ..\n"); int i = 0; pid_t pid; for (i = 0; i < 5; i++) { pid = fork(); if (pid == 0) { printf("I am child, pid = %d \n", getpid()); break; } } sleep(i); if (i == 5) { for (i = 0; i < 5; i++) { pid_t wpid = wait(NULL); printf("wpid = %d \n", wpid); sleep(1); } sleep(1); } printf("End ...\n"); return 0; }
输出结果
Begin .. I am child, pid = 76074 I am child, pid = 76075 I am child, pid = 76071 I am child, pid = 76072 I am child, pid = 76073 End ... End ... End ... End ... End ... wpid = 76071 wpid = 76072 wpid = 76073 wpid = 76074 wpid = 76075 End ...