Linux系统进程——进程的退出、子进程退出的收集、孤儿进程

news2024/11/28 16:47:05

进程退出

进程退出主要分为两种:正常退出、异常退出

正常退出

正常退出分为以下几种:

1.main函数调用return
2.进程调用exit(),标准c库
3.进程调用 _exit() 或者 _Exit() ,属于系统调用
4.进程最后一个线程返回
5.最后一个线程调用pthread exit(4和5与线程有关)

异常退出

异常退出分为以下几种:

1.调用abort函数
2.当进程收到某些信号时,如 ctrl+C
3最后一个线程对取消 (cancellation) 请求做出响应

退出函数的解析

退出函数分别有exit()、_exit()、_Exit(),其函数原型和参数如下:

函数原型所包含头文件参数
void exit(int status) <stdlib.h>exit(0)正常退出;exit(1)异常退出
void _exit(int status) <unistd.h>_exit(0)正常退出;_exit(1)异常退出
void _Exit(int status)<stdlib.h>

_Exit(0)正常退出;_Exit(1)异常退出

status 是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束;其它的值表示出现了错误,进程非正常结束在实际编程时,可以用 wait()系统调用接收子述程的返回值,针对不同的情况进行不同的处理

第二种与第三种类似,但第一种与其他两种有一定的区别,区别如下:

从图里可以看出来,_exit()函数的作用是: 直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构; 而exit()函数则在这 些基础上做了一些包装,在执行退出之前加了若干道工序. exit()函数和_exit()函数的最大区别就在于exit()函数在终止当前进程之前要检查该进程 打开过那些文件,把文件缓冲区中的内容写回文件,也就是图中的 "清楚I/O缓冲" 一项.

不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。对上述任意一种终止情形、我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit._exit和_Exit),实现这一点的方法是,将其退出状态((exit status)作为参数传送给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。

子进程退出的收集

为什么要等待子进程退出?

父进程得管理子进程,所以父进程派给子进程的任务完成的如何,我们都需要知道,如,子进程运行完成,运行结果对还是不对,或者是否正常退出 、父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

不收集子进程状态会发生什么?

子进程状态不被收集会变成僵尸进程,造成内存泄漏

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

int main()
{
	int vfork_t = 0;
	int count = 0;

	vfork_t = vfork();

	if(vfork_t > 0)
	{
		while(1)		
		{	
			printf("count = %d\n",count);
			printf("This is father,pid =%d \n",getpid());
			sleep(1);
		}
	}
	else if(vfork_t == 0)
	{
		while(1)
		{
			printf("This is child,pid =%d \n",getpid());
			sleep(1);
			count++;
			if(count == 3)
			{
				exit(0);
			}
		}
				
	}
	return 0;
}

可见父进程显示S+(正常运行),而子进程显示Z+(僵尸体(死)进程)

收集子进程的函数调用

收集子进程可以调用的函数有wait(),waitpid(), waitid()

waiit()

包含的头文件

#include <sys/types.h>
#include <sys/wait.h>

函数原型

pid_t wait(int *status);

参数解读

status参数:

一个整型数指针
非空:子进程退出状态放在它所指向的地址中
空:不关心退出状态

返回值

wait():如果成功,返回终止子进程的进程ID;错误,返回-1。

针对wait函数的参数做出试验

1.空:wait(NULL)

将上面函数vfork换成fork并调用wait函数,如下:

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

int main()
{
	int fork_t = 0;
	int count = 0;

	fork_t = fork();

	if(fork_t > 0)
	{
		wait(NULL);
		while(1)		
		{	
			printf("count = %d\n",count);
			printf("This is father,pid =%d \n",getpid());
			sleep(1);
		}
	}
	else if(fork_t == 0)
	{
		while(1)
		{
			printf("This is child,pid =%d \n",getpid());
			sleep(1);
			count++;
			if(count == 3)
			{
				exit(0);
			}
		}
				
	}
	return 0;
}

可见,在子进程运行三次后,收集子进程,轮到父进程运行,此时运行程序没有子进程,即子进程不会变成僵尸进程,而父进程正常运行

2.非空:wait(*status)

将上面函数的NULL改成定义的任意值,并通过观察该只判断子进程状态

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

int main()
{
	int fork_t = 0;
	int count = 0;
	int status = 9;

	fork_t = fork();

	if(fork_t > 0)
	{
		wait(&status);//观察子进程状态
		printf("child quit,status is %d\n",WEXITSTATUS(status));//打印子进程状态,值应为exit括号里的返回值
		while(1)		
		{	
			printf("count = %d\n",count);
			printf("This is father,pid =%d \n",getpid());
			sleep(1);
		}
	}
	else if(fork_t == 0)
	{
		while(1)
		{
			printf("This is child,pid =%d \n",getpid());
			sleep(1);
			count++;
			if(count == 3)
			{
				exit(3);
			}
		}
				
	}
	return 0;
}

可见,当指针为非空时,子进程的退出状态会保存在指向的地址中,即exit函数括号里的值会指向status的地址,从而打印判断子进程的状态。

waitpid()

 包含的头文件

#include <sys/types.h>
#include <sys/wait.h>

函数原型

pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

参数解读

pid参数:

pid的值功能
pid<-1等待进程组识别码为 pid 绝对值的任何子进程
pid=-1等待任何子进程,相当于 wait()
pid=0等待进程组识别码与目前进程相同的任何子进程
pid>0等待任何子进程识别码为 pid 的子进程

status参数:

一个整型数指针
非空:子进程退出状态放在它所指向的地址中
空:不关心退出状态

options参数:

WCONTINUEL若实现支持作业控制。那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态(POSIX.1的XSI护展)

WNOHANG

     (常用)

若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0
WUNTRACED若某实现支持作业控制,而由pid指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应于一个暂停子进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
	int fork_t = 0;
	int count = 0;
	int status = 9;

	fork_t = fork();

	if(fork_t > 0)
	{
		waitpid(fork_t,&status,WNOHANG);//第一个参数:父进程的返回值大于0,同时该返回值就是子进程的pid,而这里的参数就是子进程pid的值
		printf("child quit,status is %d\n",WEXITSTATUS(status));
		while(1)		
		{	
			printf("count = %d\n",count);
			printf("This is father,pid =%d \n",getpid());
			sleep(1);
		}
	}
	else if(fork_t == 0)
	{
		while(1)
		{
			printf("This is child,pid =%d \n",getpid());
			sleep(1);
			count++;
			if(count == 3)
			{
				exit(3);
			}
		}
				
	}
	return 0;
}

调用该函数后,子进程和父进程会一起运行,即父进程不会挂起,在运行3次之后,只有父进程运行,同时子进程此时表现为僵尸进程。

孤儿进程

父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程。 Linux避免系统存在过多孤儿进程,==init进程(系统初始化进程,进程ID为1)==收留孤儿进程,变成孤儿进程的父进程。

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

int main()
{
	int fork_t = 0;
	int count = 0;
	int status = 9;

	fork_t = fork();

	if(fork_t > 0)
	{
		printf("This is fther pid,pid is  %d\n",getpid());//打印一次父进程的pid
	}
	else if(fork_t == 0)
	{
		while(1)
		{
			printf("This is child,pid =%d,my father is %d\n",getpid(),getppid());
			sleep(1);
			count++;
			if(count == 5)
			{
				exit(3);
			}
		}
				
	}
	return 0;
}

可见,父进程打印一次,打印完之后结束,此时只剩下子进程,不难发现,子进程的父进程pid值为1,相当于系统分配了个pid值为1的父进程收留这些孤儿进程;同时子进程还在运行,不为僵尸进程。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

asp.net网上书店管理系统VS开发sqlserver数据库web结构c#编程计算机网页源码项目

一、源码特点 asp.net网上书店管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 asp.net网上书店系统1 二、功能介绍 本系统使用Microsoft Visual Studio 2019为开发工具&#xff0c;SQL Server为…

影响气膜建筑坍塌的原因

气膜建筑以其轻盈、透光、环保等特性&#xff0c;逐渐在建筑领域崭露头角。然而&#xff0c;这种建筑形式并非没有缺陷&#xff0c;其安全性与稳定性直接影响到建筑物的使用寿命和人员安全。 一、结构设计不合理 气膜建筑的结构设计是影响其稳定性的关键因素。良好的结构设计能…

LeetCode(24)文本左右对齐【数组/字符串】【困难】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 文本左右对齐 1.题目 给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单…

delphi电子处方流转 sm2 sm4(药店)

【delphi电子处方流转(药店)】支持 处方下载、处方核验、处方审核、药品销售出库明细上传、药品销售出库明细撤销等功能。技术交流Q 648437169 下载链接&#xff1a;https://download.csdn.net/download/liushenglin123/88543771

数据结构(c语言版本) 二叉树的遍历

要求 实现二叉树的创建&#xff0c;并输入二叉树数据 然后先序遍历输出二叉树、中序遍历输出二叉树、后序输出二叉树 例如二叉树为&#xff1a; 该二叉树的先序遍历结果为&#xff1a; A B D C E F 该二叉树的中序遍历结果为&#xff1a; B D A E C F 该二叉树的后序遍历结果…

从0开始学习JavaScript--JavaScript 函数

JavaScript中的函数是编写可维护、模块化代码的关键。本文将深入研究JavaScript函数的各个方面&#xff0c;包括基本语法、函数作用域、闭包、高阶函数、箭头函数等&#xff0c;并通过丰富的示例代码来帮助读者更好地理解和应用这些概念。 函数的基本语法 函数是一段可被重复…

Java网页版即时通讯聊天系统(附源码)

疫情期间,整天闷在家里又不能聚会,大把的空余时间差点让我发霉,后来有个客户发来新年祝贺,情不自禁想起了一件事情,就是他曾经提起过,要是在后台管理系统里面整合个聊天功能该多好啊,有了这个念头,马上行动起来!!! 一.系统演示 1.1 聊天窗体主界面演示 1.2 模拟两…

Java集合List报错,java.lang.UnsupportedOperationException

目录 一、点击Arrays.asList源码&#xff0c;一探究竟二、习惯了Arrays.asList&#xff0c;就是想用.add()添加元素&#xff0c;怎么办&#xff1f;三、又有一个同事&#xff0c;是这样写的四、重新点击Arrays.asList源码&#xff0c;一探究竟五、全是坑&#xff0c;怎么办&…

iframe渲染后端接口文件和实现下载功能

一&#xff1a;什么是iframe&#xff1f; 1、介绍 iframe 是HTML 中的一种标签&#xff0c;全称为 Inline Frame&#xff0c;即内联框架。它可以在网页中嵌入其他页面或文档&#xff0c;将其他页面的内容以框架的形式展示在当前页面中。iframe的使用方式是通过在HTML文档中插入…

python连接elasticsearch

问题一&#xff1a;urllib3.exceptions.ProtocolError: (‘Connection aborted.’, RemoteDisconnected(‘Remote end closed connection without response’)) 协议写错了&#xff0c;是https 问题一&#xff1a;SSLError([SSL: CERTIFICATE_VERIFY_FAILED] certificate ver…

uni-app:如何配置uni.request请求的超时响应时间(全局+局部)

方法一&#xff1a;全局配置响应时间 一、进入项目的manifest.json的代码视图模块 二、写入代码 "networkTimeout": {"request": 5000 }, 表示现在request请求响应时间最多位5秒 方法二&#xff1a;局部设置响应时间 一、直接在uni.request中写入属性…

Redis7.2.3集群安装,新增节点,删除节点,分配哈希槽,常见问题

概念&#xff1a; 【Redis】高可用之三&#xff1a;集群&#xff08;cluster&#xff09; - 知乎 实操&#xff1a; Redis集群三种模式 主从模式 优势&#xff1a; 主节点可读可写 从节点只能读&#xff08;从节点从主节点同步数据&#xff09; 缺点&#xff1a; 当主节点…

UE基础篇八:平衡蓝图与C++的使用

一、蓝图转换C++ 案例结构: 1.1 蓝图和C++对比 1.2 将蓝图变量转C++ 现在C++中定义同样的类型

【分布式】BASE理论详解

一、什么是BASE理论&#xff1f; BASE理论是对分布式系统设计和处理的一种理论指导&#xff0c;相对于ACID&#xff08;原子性、一致性、隔离性和持久性&#xff09;这一强一致性模型&#xff0c;BASE更强调在分布式系统中牺牲强一致性以获得可用性和性能的平衡。 BASE 理论是…

《硅基物语.AI写作高手:从零开始用ChatGPT学会写作》《从零开始读懂相对论》

文章目录 《硅基物语.AI写作高手&#xff1a;从零开始用ChatGPT学会写作》内容简介核心精华使用ChatGPT可以高效搞定写作的好处如下 《从零开始读懂相对论》内容简介关键点书摘最后 《硅基物语.AI写作高手&#xff1a;从零开始用ChatGPT学会写作》 内容简介 本书从写作与ChatG…

Java和JavaScript是一样的技术吗?

目录 一、Java 是什么 二、JavaScript 是什么 三、Java 和 JavaScript 的区别 一、Java 是什么 Java是一种广泛使用的计算机编程语言&#xff0c;最初由Sun Microsystems&#xff08;后被Oracle收购&#xff09;于1995年发布。Java是一种面向对象的语言&#xff0c;设计初衷…

上海亚商投顾:沪指低开低走 抖音概念股逆势爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日震荡调整&#xff0c;深成指跌超1%&#xff0c;创业板指跌超1.8%。抖音概念股逆势爆发&#xff0c;佳…

Kubernetes基础知识了解

一、Kubernetes简介 Kubernetes是一个轻便的和可扩展的开源平台&#xff0c;用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中&#xff0c;会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Google生产…

内网离线安装elasticsearch、kibana

一、软件获取 elastic kibana 二、elastic安装 解压安装即可提前可改下配置文件&#xff0c;不然可能会出现内存分配错误 三、运行elastic 需要调试看信息的话&#xff0c;可在cmd窗口运行bat&#xff0c;就会打印输出信息了。 生产kibana token bin\elasticsearch-create…

web:[BUUCTF 2018]Online Tool

题目 打开页面显示如下&#xff0c;进行代码审计 上述代码主要功能是接收‘host’参数&#xff0c;后使用nmap扫描主机端口 首先检查是否存在HTTP_X_FORWARDED_FOR头&#xff0c;若存在&#xff0c;将值赋值给EMOTE_ADDR,是为了跟踪用户真实的IP地址 后用检查get‘host’是否…