【linux】进程创建、等待、终止

创建进程fork函数
函数原型:pid_t fork(void);
返回值:子进程返回0;父进程返回子进程pid,失败返回-1(失败的原因:1内存不够;2系统进程数量太多);
注意:fork之前,父进程独立执行,fork之后,父子两个执行流分别执行。但是父子进程谁先执行是由系统调度决定。
写实拷贝:父进程创建子进程后,子进程室父进程的副本;父子代码共享,父子不写入时,数据也是共享。当任意一方试图写入时,便以写实拷贝的方式各自创建一份副本。
这里写图片描述
代码:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3          
  4 int main()
  5 {        
  6     pid_t pid = fork();
  7     if(pid>0){
  8         sleep(3);
  9         printf("I am father:%d\n",getpid());
 10     }else if(pid==0){
 11         printf("I am child:%d\n",getpid());
 12         sleep(1);                                                                                                                               
 13     }else{
 14         perror("fork");
 15     }    
 16     return 0;
 17 } 

这里写图片描述
vfork函数:也是创建进程,用法跟fork相似;
不同的是:
1、vfork一个子进程,父子进程共享地址空间,而fork的子进程具有独立的地址空间。
2、vfork保证子进程先运行,直到调用exec或者exit之后父进程才运行。

代码:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 int flag = 100;//设定一个全局变量100
  5 int main()
  6 {        
  7     pid_t pid = vfork();
  8     if(pid>0){
  9         sleep(2);
 10         flag = 10;//父进程把flag变为1011         printf("father:%d;flag = %d\n",getpid(),flag);
 12         exit(0);
 13     }else if(pid==0){
 14         flag = 0;     //子进程把flag变为0printf("child:%d,father_id=%d,flag=%d\n",getpid(),getppid(),flag);
 16         sleep(5);
 17     }else{
 18         perror("fork");
 19     }    
 20     return 0;
 21 }  

结果:
这里写图片描述
我们看到子进程改变了父进程的的值,因为子进程实在父进程的地址空间运行。

进程等待wait和waitpid
进程等待必要性:
1、子进程退出,如果父进程不管不顾,就可能造成僵尸进程的问题,造成内存泄露。
2、父进程需要知道子进程的退出状态,完成的任务结果如何。
3、父进程通过进程等待的方式,回收子进程资源,获取子进程退出状态。
函数原型:pid_t wait(int *status)
返回值:成功返回被等待进程的pid;失败返回-1;
参数:输出型参数,获取子进程的退出状态,不关心可以设置为NULL;
status&0x7f==0:表示代码执行完了,正常退出;
status&0x7f!=0:表示异常退出,具体值表示使该进程退出的信号的编码。
status>>8 & 0xff的值表示子进程的退出码。
调用wait函数会发生什么?
1. 如果有子进程在运行,父进程进入阻塞状态(可以理解为什么事情都没有做,一直在检测子进程是否在运行)
2.如果父进程在调用wait前子进程已经终止,wait可立即获得子进程的终止状态(退出码,退出信息),子进程的终止状态是体现在status参数上的,另外wait还会返回所终止的子进程的标识符。
3.如果当前没有子进程,则会出错返回-1。
4.如果有一个子进程终止,那么wait便返回。
这里写图片描述

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/wait.h>
  5  
  6 int main()
  7 {
  8     int ret=fork();
  9     if(ret>0){
 10         int status=0;
 11         int wait_id = wait(&status);
 12         if(wait_id>0){
 13             printf("child has success dead!,id=%d\n",wait_id);
 14         }else{
 15             printf("child has false dead!,%d\n",wait_id);
 16         }
 17     }else if(ret==0){
 18         printf("I am child,id=%d\n",getpid());
 19         sleep(5);
 20         exit(0);
 21     }else{
 22         perror("fork");
 23     }
 24     return 0;
 25 }     

这里写图片描述

waitpid函数:也是创建进程,用法跟wait相似;
函数原型:pid_t waitpid(pid_t pid,int *status,int options)
pid:检测子进程的pid
status:子进程的终止状态,如果不是空指针,则终止进程的终止信息就存放在它所指向的单元内。不关心终止状态可以将status制成NULL。
options:指定参数,默认情况下waitpid与wait做的事情都是一样的,为阻塞式监测子进程终止状态;当options=WNOHANG时,此时为非阻塞方式,就是监测时如果子进程没有终止,调用者可以做其他事情,另外还有两个参数分别为WCONTINUED和WUNTRACED,这两个参数是跟作业控制有关的。
这里写图片描述
结果:
这里写图片描述
非阻塞等待:
这里写图片描述
结果:
这里写图片描述
WNOHANHG:若子进程没有结果,waipid返回0,不予等待,若正常结束,则返回该子进程的pid。
WIFEXITED(status):表示若为正常终止子进程返回的状态,则为真(查看进程是否是正常退出),这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值;
WEXITSTATUS(status):若WIFEXITED非零,提取子进程的退出码(查看进程退出码)。

进程终止_exit()和exit()
查看进程退出码: echo $?

#include<unistd.h>
void _exit(int status)
参数:status定义了程序的终止状态,父进程通过wait获取该值。

#include<unistd.h>
void exit(int statsu)

_exit()系统调用 exit() 库函数
exit()做的三件事:
1,执行用户通过atexit或者on_exit定义的清理函数
2,关闭所有打开流,所有的缓存数据均被写入。
3,调用_exit;

思考题:vfork创建的子进程, 直接return为什么会出现崩溃?
结束子进程的调用是exit()而不是return,如果你在vfork中return了,那么,这就意味main()函数return了,注意因为函数栈父子进程共享,所以整个程序的栈就出现问题了。

猜你喜欢

转载自blog.csdn.net/prefect_boy/article/details/78787376