文章目录

  • 引言
  • 一,fork()
    • 1. 常规用法
    • 2. 它和写时拷贝的关系
  • 二,进程终止
    • 1. 退出码
    • 2. exit()和_exit()的关系
  • 三,进程等待
    • 1. 什么是进程等待
    • 2. 为什么要进程等待
    • 3. 进程如何等待
      • 1. wait()
      • 2. waitpid()
        • status
        • options

引言

我们知道在linux系统中,一个父进程创建了一个子进程,此时子进程如果退出了,他就会保持僵尸状态,而僵尸状态的进程是有弊端的,虽然已经退出,但是
还在消耗内存资源。linux系统对内存的管理当然是相当的严格高效的,绝对是不允许这种浪费资源的事情发生的,那么linux系统会对僵尸状态的进程进行怎
么样的处理呢?

在解决这个问题之前,我们先了解一下预备知识

一,fork()

  • 函数fork()是用来启动另一个进程的函数,启动起来的进程称为子进程在调用fork()函数的程序称为父进程
  • 子进程的大部分数据都是拷贝于父进程的,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定

1. 常规用法

  • 一个进程要执行不同的程序。eg:子进程从fork()返回后,调用exec()。
  • 一个父进程希望复制自己,使父子进行不同的代码段。eg:父进程等待客户端请求,子进程来处理请求。

2. 它和写时拷贝的关系

上面说道,子进程的大部分数据都是来源于父进程的,在linux这个对内存要进行高效利用的系统中,子进程的创建显然不会对他从父进程里继承的全部数据马上分配内存空间,这时系统会先给子进程和父进程一样的虚拟地址,当子进程真正需要修改数据时系统才会进行拷贝一块内存给子进程用,这就是写时拷贝。

二,进程终止

三种情况

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止(本质:因为某些原因,收到操作系统的信号)

1. 退出码

我们在学习C语言时,是不是常常在main函数里面return 0,这其中的0就是我们学习的退出码,0是众多退出码的一种,表示程序代码正常终止。
我们来看看退出码的数量和含义:

在C语言中,有一个专门打印退出码含义的函数strerror(),下面我们通过代码来演示

#include<stdio.h>
#include<string.h>
int main()
{int i = 0;for ( i = 0; i < 150; ++i)printf("%d:%s\n",i,strerror(i));return 0;
}


从图中我们可以看出,一共有134个退出码,常用的是0表示正常退出,在linux操作系统下,我们可以通过echo $?来查询上一个执行完的程序的退出码

第一个echo $?获取到的退出码是刚刚执行的程序是正常退出的,第2,3个都是系统指令返回的退出码,第4,5表示echo $?自身执行成功返回的退出码。

2. exit()和_exit()的关系

我们先看关于exit()和_exit()的两段代码,同过比较,来学习一下两者的相同点和不同点。

  • exit()
#include<stdio.h>
#include<stdlib.h>
int main()
{printf("%s",strerror(0));exit(2);printf("\n");return 0;
}

  • _exit()
#include<stdio.h>
#include<unistd.h>
int main()
{printf("%s",strerror(0));exit(2);printf("\n");return 0;
}

  • 相同点:exit和_exit都可以在任何地方正常退出程序,并返回退出码。eg:上述代码就返回了2,并都没有执行printf("\n");.
    -不同点:exit()除了会正常退出程序外,他还会清理函数,刷新缓冲区,_exit()则直接正常退出程序。
底层可以这么理解,exit 调用 _exit
exit(int code)
{关闭文件,清理函数;刷新缓冲区;_exit();
}

三,进程等待

通过上面的知识了解,现在我们来解决开头的问题:父进程如何对僵尸进程进行处理

1. 什么是进程等待

父进程为了拿到子进程的运行信息结果对子进程进行资源回收的等待过程

2. 为什么要进程等待

  1. 我们知道子进程结束后,如果父进程不做任何处理,那么子进程就会变成僵尸状态,而僵尸状态的进程刀枪不入,kill -9 也杀不死它,所以会造成资源浪费,所以需要父进程调用wait() / waitpid() 来回收子进程的资源。
  2. 获取子进程的结果。
  3. 保证时序。让子进程先退出,父进程后退出。

3. 进程如何等待

1. wait()

父进程执行到wait()时,就进入阻塞状态,一直等待子进程的结束。便于观察,我多加了几个sleep()。代码如下:

void test_wait()
{pid_t pid = fork();if(pid == 0){int i = 5;while(i--){printf("%d,子进程,pid=%d\n",i,getpid());sleep(1);}exit(0);}sleep(6);printf("等待wait回收子进程资源...\n");wait(NULL);printf("子进程终于结束了,我是父进程,获取到子进程的pid=%d\n",pid);sleep(2);
}


红色框:父子进程一并运行。
蓝色框:子进程结束,进入僵尸状态,等待父进程用wait()来进行资源回收。
黄色框:子进程的僵尸状态消失,只剩父进程在运行。

ps:这里解释一下为什么父子进程全程都是S+(阻塞状态)。根据代码,如果去掉sleep(),其中在红色框时,子进程应该是R+(运行状态),父进程是S+,因为父进程调用了wait(),需要等待子进程运行完毕才会继续下面代码的执行。后面蓝色和黄色框框父进程是R+。

2. waitpid()

来看看waitpid()的形式参数


有三个,其中第二个和wait(*status)一样,上面没说,那么现在来学习一下。

  1. pid:子进程的pid,-1表示任意子进程
  2. status:一种状态码(一会就详谈)
  3. options:子进程状态。常用的:0表示阻塞状态,WNOHANG表示非阻塞状态

wait(NULL)相当于waitpid(pid, NULL,0),pid表示子进程的pid。可以简单理解为waitpid()wait()的升级版。

status

status的大小为4个字节,有32位,我们探究其后16位。

现在我们通过代码来看看

void test_wait()
{pid_t pid = fork();if(pid == 0){int i = 5;while(i--){printf("%d,子进程,pid=%d\n",i,getpid());sleep(1);}exit(3);}sleep(6);printf("等待wait回收子进程资源...\n");int status = 0;wait(&status);printf("子进程终于结束了,我是父进程,获取到子进程的pid=%d\n",pid);printf("退出码:%d,终止信号:%d\n",(status>>8)&0xff,status&0x7f);sleep(2);
}

  • 这里3是子进程退出的返回值,我们用了exit(3)来显示表示,终止信号0表示正常运行,没有发生异常。
  • status的引入可以让我们更好了解到子进程的运行信息。
  • waitpid()/wait() 通过修改子进程的pcb来返回status的信息。

status其实可以用系统提供的宏定义WIFEXITED(STATUS)来判断是非是正常退出,用WIFSTATUS(STATUS)获取进程退出码

options

在学习wait()的时候,我们有提到过,子进程在运行时,父进程在阻塞,这是对的,经过我们验证的。因为**wait()是默认让父进程进行阻塞状态**,而waitpid()却有options这个参数来控制父进程的状态。
下面我们来看看

void test_wait()
{pid_t pid = fork();if(pid == 0){int i = 5;while(i--){printf("%d,子进程,pid=%d\n",i,getpid());sleep(1);}exit(0);}//sleep(6);//printf("等待wait回收子进程资源...\n");int status = 0;waitpid(pid, &status, WNOHANG);int i = 0;for(i = 0; i < 5; ++i){printf("我是父进程,我先做自己的事情...\n"); sleep(1);}printf("子进程终于结束了,我是父进程,获取到子进程的pid=%d\n",pid);printf("退出码:%d,终止信号:%d\n",(status>>8)&0xff,status&0x7f);sleep(2);
}

可以看到,父进程并没有等待子进程运行完才执行自己的事情,而是并发执行,两种执行顺序没有先后之分,由操作系统来调度。

linux之《进程等待》相关推荐

  1. 【Linux】进程等待wait/waitpid status详解 (非)阻塞等待(代码)

    文章目录 进程等待原因 进程等待方法 wait waitpid 获取子进程status (非)阻塞等待 进程的非阻塞等待方式代码 进程的阻塞等待方式代码 进程等待原因 fork创建了子进程,子进程帮父 ...

  2. LInux:进程等待之wait() waitpid()

    进程等待 之前说,子进程退出,父进程如果不管不顾,就可能造成"僵尸进程"的问题,进而造成内存泄露,进而,进程一旦变成僵尸状态,杀人不眨眼的"kill -9"也无 ...

  3. linux 主进程 等待,Linux启动与进程

    操作系统中,前台进程和后台进程有什么区别?特征是什么? 后台程序基本上不和用户交互,优先级别稍微低一点 前台的程序和用户交互,需要较高的响应速度,优先级别稍微高一点 直接从后台手工启动一个进程用得比较 ...

  4. 【看表情包学Linux】进程等待 | wait/waitpid 的 status 参数 | 获取退出码与退出信号 | 初识核心转储

  5. linux编程取消wait函数,Linux编程基础之进程等待(wait()函数).pdf

    Linux编程基础之进程等待(wait()函数) 编程过程中,有时需要让一个进程等待另一个进程 ,最常见的是父进程等待自己的子进程 ,或者父进程回收自己 的子进程资源包括僵尸进程.这里简单介绍一下系统 ...

  6. Linux内核中的进程等待与其实现解析

    一.进程等待的概述 进程通过 fork 产生子进程,进程也会死亡,进程退出的时候将会进行内核清理,释放所有进程的资源,资源包括:内存资源,文件资源,信号量资源,共享内存资源,或者引用计数减一,或者彻底 ...

  7. Linux 进程控制 :进程创建,进程终止,进程等待,程序替换

    进程创建 进程终止 进程等待 程序替换 进程创建 fork函数 创建一个子进程,父子进程代码共享,数据独有 #include <unistd.h> pid_t fork(void); 返回 ...

  8. linux下的C语言开发(进程等待)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 所谓进程等待,其实很简单.前面我们说过可以用fork创建子进程,那么这里我们就可以使用wait ...

  9. linux进程等待wait()实例

    在Linux系统中,进程的生命周期内主要包含:进程就绪.进程执行.进程等待和进程退出. 就绪转执行 处于就绪状态的进程,当进程调度程序为之分配了处理机(CPU)后,该进程便由就绪状态转变成执行状态. ...

  10. 【Linux】linux进程--进程控制:进程创建、进程终止、进程等待、进程程序替换

    目录 1.进程创建 1)重温fork():让正在运行的进程创建出来一个子进程:从已存在的进程中创建一个新的进程,新进程为子进程而远进程为父进程. 2)fork内部完成的事情 3)用户空间 & ...

最新文章

  1. 从命令行使用 wget 调试网页错误
  2. vector使用排序函数实例
  3. Python零碎知识(6):split 和 join
  4. 用rate-limit来限制特定用户的流量
  5. ubuntu21.04截图快捷键
  6. 基于mykernel完成多进程的简单内核
  7. STM32F7xx —— ADC
  8. 如何登陆网页的back office_如何使用iPhone面容ID快速登陆应用或网页
  9. DataGrid中加入CheckBox,并实现单选 选择自 listhome 的 Blog
  10. CSS实现三栏布局(5种)
  11. 离散数学复习笔记(已完结)
  12. 【数据结构 严蔚敏版】 顺序栈 基本操作
  13. 在线画图工具绘制流程图怎样做
  14. lpddr3 阻抗_LPDDRx的总结
  15. xlsxwriter
  16. hdu 1880 魔咒词典 (字符串哈希)
  17. Python的模块和包管理
  18. 植物大战僵尸_修改存档和金钱
  19. PCB板的绘制原来是这样完成的——布线
  20. 丽台 A6800XT TDH (AGP) 显卡软件开管和超频手记

热门文章

  1. GPIO模式运用场合详解
  2. mysql错误18456_SQL Server登录 18456错误
  3. linux 日常工作常用软件(持续更新)
  4. databinding找不到符号
  5. 微服务架构: 基于nacos注册中心的Zuul网关实现
  6. GBDT + LR模型融合
  7. 如何使用Python轻松解决TSP问题(PSO算法)
  8. java的jvm是指_java JVM原理与常识知识点
  9. cherry-pick的使用过程
  10. Java常用的格式化Json工具类