[linux]进程控制——进程等待

一、概念

进程等待,就是通过wait/waitpid的方式,让父进程(一般)对子进程进行资源回收的等待过程。

二、原因

(1)

当一个进程在退出的时候,如果不回收,就会变成僵尸状态,它让父进程等待之后,将僵尸状态进行回收。

僵尸就是进程或者子进程对应的代码和数据已经被释放,但是它的PCB以及它进程退出的相关数据依旧被维护,需要让父进程得知它的退出结果。

总结:

解决子进程僵尸问题带来的内存泄漏问题(是必须的)

(2)

父进程创建子进程,是为了让子进程帮助父进程完成父进程分配给子进程的任务。

所以,父进程需要知道子进程任务的完成情况。

总结:

需要通过进程等待的方式,获取子进程退出的信息。(不是必须的,但是系统需要提供这样的基础功能(可以不用,但不能没有))

三、如何实现进程等待

1、wait

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);

返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

演示:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(0);
  }
  else 
  {
    sleep(10);
    pid_t rid = wait(NULL);
    if(rid == id)
    {
      printf("wait sucess, pid:%d\n",getpid());
    }
  }



  return 0;
}
运行结果:

监视:

可以看出子进程运行完毕之后,在父进程sleep的时间内,子进程是Z状态(僵尸状态)

随后父进程wait,子进程被回收,不再是僵尸状态。

 

思考:

如果将代码中的sleep(10)删除,即表示父进程一开始直接执行到wait,那么情况又是什么样的呢?

运行结果:

 

监视:
 
总结:

进程等待能够回收子进程僵尸状态,Z->X

如果子进程没有退出,父进程必须在wait上进行阻塞等待,直到子进程僵尸,wait自动回收,返回。

 

2、waitpid

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID

演示:

(1)效果与wait相同

 waitpid(id,NULL,0)

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(0);
  }
  else 
  {
  //  sleep(10);
    printf("wait before\n"); 
   // pid_t rid = wait(NULL);
    pid_t rid = waitpid(id,NULL,0);
    
    printf("wait after\n");

    if(rid == id)
    {
      printf("wait sucess, pid:%d\n",getpid());
    }
  }



  return 0;
}

(2) status

status是一个int的整数,32bit,我们只考虑status的低16位。status的低16位被划分为三部分:

它的低七位是对应的信号,次低八位是退出的退出码。而剩下的1个bit位是core dump标志。

 

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(2);
  }
  else 
  {
  //  sleep(10);
    printf("wait before\n"); 
   // pid_t rid = wait(NULL);
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    
    printf("wait after\n");

    if(rid == id)
    {
      printf("wait sucess, pid:%d, status:%d\n",getpid(), status);
    }
  }



  return 0;
}

 

思考:

我们设置的退出码是2,那么为什么status显示的是512呢?

 退出码是2,根据上面status比特位的分区,我们可以写出status低16位:

那么该二进制转换成十进制,就是512。

 所以,我们不能对status进行整体使用。

使用:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>


void Worker()
{
  int cnt = 5;
  while(cnt)
  {
    printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);
    cnt--;
    sleep(1);
  }
}

int main()
{
  pid_t id = fork();

  if(id == 0)
  {
    //子进程
   Worker();
   exit(2);
  }
  else 
  {
  //  sleep(10);
    printf("wait before\n"); 
   // pid_t rid = wait(NULL);
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    
    printf("wait after\n");

    if(rid == id)
    {
      printf("wait sucess, pid:%d, rpid:%d, exit sig:%d, exit code:%d\n",getpid(), rid, status&0x7F, (status>>8)&0xFF);
    }
  }



  return 0;
}

 

如此,我们就可以正确显示该进程的退出信号和退出码了。

总结:
  1. 当一个进程异常(收到信号),exit code是没有意义的。
  2. 判定有没有收到信号,exit sig:0(sucess)
  • exit sig:0,exit code: 0 :代码跑完,结果正确。
  • exit sig:0,exit code: 非0 :代码跑完,结果不正确。
  • exit sig:非0   :中间出异常,exit sig的数字表明出现了哪种异常。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/561588.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】——内存函数的使用及模拟实现

【C语言】——内存函数的使用及模拟实现 前言一、 m e m c p y memcpy memcpy 函数1.1、函数功能&#xff08;1&#xff09;函数名理解&#xff08;2&#xff09;函数介绍 1.2、函数的使用1.3、函数的模拟实现 二、 m e m m o v e memmove memmove 函数2.1、函数功能2.2、函数的…

Vulnhub靶机 DC-6 打靶实战 详细渗透测试过程

Vulnhub靶机 DC-6 详细渗透流程 打靶实战 目录 Vulnhub靶机 DC-6 详细渗透流程 打靶实战一、将靶机导入到虚拟机当中二、渗透测试主机发现端口扫描信息探测web渗透目录爆破爆破后台密码反弹shell搜集有价值信息SSH远程登录提权反弹jens用户权限的shell 提权利用 一、将靶机导入…

Mac 下安装PostgreSQL经验

使用homebrew终端软件管理器去安装PostgreSQL 如果没有安装brew命令执行以下命令 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 沙果开源物联网系统 SagooIoT | SagooIoT 1.使用命令安装postgreSQL brew i…

制作一个RISC-V的操作系统十二-定时器中断

文章目录 CLINT定时器中断mtimemtimecmp机制总体框架流程时间节拍系统时钟代码 CLINT 产生软件中断和定时器中断 定时器中断 mtime 类似计数器&#xff0c;按照硬件对应的固定频率递增 上电后会自动复位为0&#xff0c;有硬件自动完成 mtimecmp 需要自己设置&#xff0…

【SpringBoot实战篇】获取用户详细信息

1 明确需求 1需要获取用户详细信息 2 接口文档 1基本信息 2请求参数 无 3 响应数据 响应数据类型&#xff1a;application/json 响应参数说明&#xff1a; 响应数据样例 3 思路分析 1用户名在请求头里获取 4 开发 4.1 控制器usercontroller GetMapping("/userInfo")p…

Vue3——组件基础

组件基础 1. 组件定义与使用 1.1 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>组件基础&l…

iZotope RX 10 音频修复和增强工具 mac/win

iZotope RX 10 for Mac是一款出色的音频修复和增强工具&#xff0c;凭借其卓越的音频处理技术&#xff0c;能够轻松应对各种音频问题。 无论是背景噪音、回声还是失真&#xff0c;RX 10都能精准去除&#xff0c;还原清晰纯净的音频。同时&#xff0c;它还提供了丰富的增强工具&…

小红书电商运营实战课,从0打造全程实操(65节视频课)

课程内容&#xff1a; 1.小红书的电商介绍 .mp4 2.小红书的开店流程,mp4 3.小红书店铺基础设置介绍 ,mp4 4.小红书店铺产品上架流程 .mp4 5.客服的聊天过程和子账号建立 .mp4 6.店铺营销工具使用和后台活动参加 .mp4 7.小红书产品上架以及拍单教程,mp4 8.小红书如何选品…

第15届蓝桥杯题解

A题 结果&#xff1a;2429042904288 思路很简单 前20个数分别是 20 24 40 48 60 72 80 96 100 120 140 144 160 168 180 192 200 216 220 240 第2 4 6 8 12 ...n个数分别是24的 1倍 2倍 3倍 4倍 6倍 n/2倍 所以第202420242024 个数就是 24的 101210121012倍 B题 答案&am…

在PostgreSQL中如何实现递归查询,例如使用WITH RECURSIVE构建层次结构数据?

文章目录 解决方案使用WITH RECURSIVE进行递归查询示例代码 总结 在PostgreSQL中&#xff0c;递归查询是一种非常强大的工具&#xff0c;它可以用来查询具有层次结构或树形结构的数据。例如&#xff0c;你可能会在员工-经理关系、目录结构或组织结构图中遇到这样的数据。为了处…

嵌入式物联网实战开发笔记-乐鑫ESP32开发环境ESP-IDF搭建【doc.yotill.com】

乐鑫ESP32入门到精通项目开发参考百例下载&#xff1a; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;4e33 3.1 ESP-IDF 简介 ESP-IDF&#xff08;Espressif IoT Development Framework&#xff09;是乐鑫&#xff08;Espressif Systems&#xff09;为 ESP 系列…

跨站攻击CSRF实验

1.low等级 先利用Burp抓包 将get响应的url地址复制&#xff0c;发到网页上&#xff08;Low等级到这完成&#xff09; Medium&#xff1a; 再将抓到的包发到Repeater上,对请求中的Referer进行修改&#xff0c;修改成和url一样的地址&#xff0c;修改成功。 在这里修改后发送 然…

Java中的四种引用类型

6.Java中的引用类型 1.强引用 一个对象A被局部变量、静态变量引用了就产生了强引用。因为局部变量、静态变量都是被GC Root对象关联上的&#xff0c;所以被引用的对象A&#xff0c;就在GC Root的引用链上了。只要这一层关系存在&#xff0c;对象A就不会被垃圾回收器回收。所以只…

Fannel和Calico

一 1、路由器下面每一个端口都是一个vlan,隔离了广播包 192.168.1.0和192.168.2.0他们属于不同的vlan,没有三层交换机或者路由器,他们通不了信 不在同一个vlan,也就是子网,包就会走向网关(也就是路由器那里,路由器有路由表。查看目的地192.168.2.0在b口,从b口出去vlan…

Axure RP 9中文激活版:专业原型设计工具mac/win

Axure RP 9是一款由美国Axure Software Solution公司开发的专业原型设计工具。它凭借强大的交互功能和丰富的设计素材&#xff0c;为产品经理、UI设计师、交互设计师等用户提供了高效、便捷的原型设计体验。 Axure RP 9支持快速创建线框图、流程图、原型和规格说明文档&#xf…

Python可视化数据分析-饼状图

一、前言 饼状图&#xff08;Pie Chart&#xff09;是一种常用的数据可视化图表&#xff0c;用于展示数据中各部分的占比关系。Python 中有多种库可以用于绘制饼状图&#xff0c;比较常用的包括 matplotlib、pyecharts和 plotly 等。 二、使用 matplotlib 绘制饼状图 import…

【Java并发知识总结 | 第八篇】Java并发线程知识总结

文章目录 8.Java线程知识总结8.1线程定义8.2Java中创建线程的三种方式8.2.1继承Thread类8.2.2实现Runnable接口8.2.3实现Callable接口&#xff08;与线程池搭配使用&#xff09;8.2.4小结 8.3线程的六种状态8.4sleep()和wait()的区别8.5线程上下文切换8.6线程之间的通信方式8.6…

【正则表达式】正则表达式基本语法元素

目录 字符类量词边界匹配逻辑和分组转义和特殊字符验证正则表达式是否能够成功提取数据 字符类 .&#xff1a;匹配除换行符之外的任何单个字符。 [abc]&#xff1a;匹配方括号内的任何字符。 [^abc]&#xff1a;匹配不在方括号内的任何字符。 [a-z]&#xff1a;匹配任何小写字…

51单片机入门_江协科技_31~32_OB记录的自学笔记_LCD1602液晶显示屏

31. LCD1602 31.1. LCD1602介绍 •LCD1602&#xff08;Liquid Crystal Display&#xff09;液晶显示屏是一种字符型液晶显示模块&#xff0c;可以显示ASCII码的标准字符和其它的一些内置特殊字符&#xff0c;还可以有8个自定义字符 •显示容量&#xff1a;162个字符&#xff0c…

使用Redis实现全局唯一ID

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 在分布式系统中&am…