/* #include <sys/types.h> #include <unistd.h> pid_t fork(void); 作用:创建子进程 返回值: fork()返回值会返回两次,一次是在父进程中,一次是在子进程中 在父进程中返回创建的子进程的ID, 在子进程中,返回0 如何区分父进程和子进程,通过fork的返回值 在父进程中返回-1,表示创建子进程失败,并且设置errno 父子进程之间的关系: 区别: 1.fork()函数的返回值不同 父进程中:>0,返回子进程的PID 子进程中:=0 2.pcb中的一些数据 当前进程的id pid 当前进程的父进程的id ppid 信号集 共同点: 某些状态下,子进程刚被创建出来,还没有执行任何的写数据操作 -用户区的数据 -文件描述符表 父子进程对变量是否是共享的 -刚开始是一样的,如果修改类数据,就不共享了 读时共享(子进程刚创建),写时拷贝 父子进程之间不能用变量进行通信,它们之间互不影响 */ #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main() { int num =10; //创建子进程 pid_t pid = fork();//pid_t本质上是int类型的 //判断是父进程还是子进程 if(pid>0){ printf("pid : %d\n", pid); //如果大于0,返回的是创建的子进程的id,当前是父进程 printf("i am parent process,pid : %d, ppid:%d\n",getpid(),getppid()); printf("parent num: %d\n",num); num+=10; printf("parent num+=10: %d\n",num); }else if(pid == 0) { //当前是子进程 printf("i am child process, pid :%d,ppid : %d\n",getpid(),getppid()); printf("child num: %d\n",num); num+=100; printf("child num+=100: %d\n",num); } for(int i =0;i<3;i++)//默认父子进程都会去执行 { printf("i : %d\n", i); sleep(1); } return 0; }
exec函数族
可执行文件的用户区去替换进程中的用户区,一般情况下会创建一个子进程,在子进程创建exec函数族中的函数
查看execl
子进程被替换掉
execlp
/*#include <unistd.h> extern char **environ; int execlp(const char *file, const char *arg, ...); -会到环境变量中查找指定的可执行文件,如果找到了就执行,找不到就 参数:-file:需要指定的执行的可执行文件的文件名 a.out ps -arg:是执行可执行文件所需要的参数列表 第一个参数一般没有什么作用,为了方便一般写的执行的参数的名称,从第二个人参数开始往后,就是程序执行所需要的参数列表 参数最后需要以NULL结束(哨兵) 返回值:-仅仅在出错的时候返回,返回-1,并且设置errno 如果调用成功,就没有返回值 */ #include <unistd.h> #include <stdio.h> int main() { //创建一个子进程在子进程中执行exec函数族中的函数 pid_t pid =fork(); if(pid >0){ //父进程 printf("i am parent process,pid : %d\n",getpid()); sleep(1); }else if(pid == 0) { //子进程 execlp("ps","ps","aux",NULL); printf("i am child process , pid:%d\n",getpid()); } for(int i =0;i<3;i++){ printf("i=%d , pid = %d\n",i,getpid()); } return 0; }
第一个参数是可执行程序的程序名,第二个参数
进程控制
fork函数 读时共享,写时复制 主要目的是降低内存的使用
子进程退出,父进程能得到子进程退出的状态 父进程有义务回收子进程的资源
#include <stdlib.h> #include<unistd.h> #include <stdio.h> int main() { printf("hello\n"); printf("world"); exit(0); return 0; //和exit是一样的,都表示进程退出 }
结果 exit() 从图中两者的功能对比可以知
将exit()改成_exit()后 world在缓冲区里
孤儿进程
父进程运行结束,子进程还在运行,这样的子进程称为孤儿进程
? 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init ,而 init进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表出面处理它的一切善后工作。
孤儿进程并不会有什么危害
如下,1领养了孤儿进程 ,由1进程回收资源
父进程结束后,显示了一个终端(回到前台)
为什么都显示在终端?父子进程的内核去的一些部分是共享的 文件描述符表前三个(0,1,2)标准输入,输出,错误
僵尸进程
? 每个进程结束之后, 都会释放自己地址空间中的用户区数据,内核区的 PCB 没有办法自己释放掉,需要父进程去释放。
? 进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸
(Zombie)进程。
僵尸进程不能被kii -9杀死