【Linux系统】进程控制

再次理解进程

进程:内核的相关管理数据结构(task_struct(进程控制块PCB),mm_struct(地址空间),页表) + 代码和数据

那么如何理解进程具有独立性

我们之前已经学习过进程控制块啊,地址空间啊,页表啊,他们不都是随着进程的创建而被创建,所以每个进程都有独立的一份这三个结构,那代码是共享的,数据是经过写时拷贝实现进程之间的独立的。

fork函数的返回

fork子进程返回0

fork父进程返回是子进程的pid

为什么父进程返回的是子进程的PID,给子进程返回的是0!!!

首先我们为了父进程方便对子进程进行标识,进而进行管理。

退出码?退出信号?

我们在写c/c++main函数的时候我们是不是往往都会写一个return 0来结束程序的运行!

为什么?

我们在命令行中使用echo $?内键命令

会发现打印出我们刚刚通过./运行的程序的main函数的返回值,我们把return后面设置为什么就会为我们返回什么!

我们知道,内键命令打印的都是bash内部的变量数据。

所以父进程bash获取到的是,最近一个子进程退出的退出码

告诉关心方(父进程),我任务完成的怎么样了!

实际上0代表成功,非0代表失败。

这是程序的退出码

1、2、3……不同的非零值,一方面表示失败,一方面表示失败的原因,

它们都有对应的错误描述,可以以字符串的形式打印出来!

父进程bash为什么要得到子进程的退出码呢?

这是要知道子进程的退出情况(成功,失败,失败的原因是什么?)

这些不都是为了让我们用户看到吗,为我们用户负责!!!

退出码不仅可以使用默认的,也可以进行自定义!

进程的终止

1.进程的终止在做什么?

释放曾经的代码和数据所占用的空间

释放内核数据结构(task_struct)-->我们知道子进程结束,父进程一直在跑但什么事情都不做,子进程进入Z(僵尸态),此时就是task_struct仍然存在的原因,这样就会造成内存泄露的问题。

那么进程的终止不就是回收资源,防止内存泄露吗!

2.进程终止的三种情况?

a.代码跑完,结果正确

可以通过进程的退出码决定!!!

b.代码跑完,结果不正确

同样可以通过进程的退出码决定!!!

c.代码执行时,出现了异常,提前退出了

两个原因,一个系统检测到错误,异常退出,一个我们人为自定义!0退出码

异常退出?(本质是因为进程收到了OS发给进程的信号!)

vs编程运行的时候,崩溃了 --- 操作系统发现你的进程做了不该做的事情,OS杀了进程,一旦出现异常,退出码没有意义了!!!

我为什么出现了异常?原因是?进程出异常,本质是因为进程收到了OS发给进程的信号!

我们可以写一段野指针的操作代码来观察现象

我们发现运行时是出现了段错误,OS提前终止进程。

当我们启动一个进程也可以用kill -11 pid来终止一个进程,其实这就是我们手动发给进程一个信号,让进程异常终止,报的也就是上面的段错误,所以进程出异常,本质是因为进程收到了OS发给进程的信号!

我们可以看进程退出的时候,退出信号是多少,就可以判断我的进程为什么异常了!!!

总结

所以我们面对程序出现错误,两步判断就可

  1. 先确认是否是异常
  2. 不是异常就一定是代码跑完了,看退出码就行。

最后,我们说衡量一个进程退出,我们只需要两个数字退出码,退出信号

这些都是要让父进程bash知道。

其实退出码,退出信号就是在我们的task_struct源代码中的两个个变量

inr exit_code,int exit_signal

3.如何终止?

a.main函数return表示进程终止(非main函数return,函数结束)

b.代码调用exit函数(注意:我们代码的任意位置调用exit,都表示进程退出)

c._exit() --- system call 系统调用接口

exit与_exit都可以让进程退出,那么它俩有什么区别呢?

exit vs _exit:exit会在进程退出的时候,充刷缓冲区,_exit不会,其实这是因为exit是c语言的库函数,它的底层还会调用_exit这个系统调用接口,来操作操作系统,所以充刷缓冲区应该在exit函数用户层的操作。

注意:目前我们说的缓冲区不是内核缓冲区!!!

4.进程等待?

是什么?

结论:任何子进程,在退出的情况下,一般必须要被父进程进行等待。进程在退出的时候,如果父进程不管不顾,退出进程,状态Z(僵尸态),造成内存泄漏。

为什么?

1.父进程通过等待,解决子进程退出的僵尸问题,,回收系统资源(一定要考虑的)

2.获取子进程的退出信息,知道子进程是因为什么原因退出的(可选的功能)

怎么办?

父进程可以通过调用wait/waitpid函数来做到上面两个事情

pid_t wait(int* status)

如果子进程没有退出,父进程其实一直在进行阻塞等待

参数部分,等待父进程中,等任意一个子进程退出。

返回值,等待成功时,子进程的pid。

进程阻塞等待?

子进程本身就是软件,父进程本质是在等待某种软件条件就绪,你如何理解阻塞等待子进程呢?

status是什么呢?

这里就要讲讲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。
 

  • 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。
  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。
  • 如果不存在该子进程,则立即出错返回。
  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整形来看待,可以当作位图来看待。

所以status其实是个输出型参数,我们学过scanf函数,我们从键盘输入数据输出到一个变量中,status就类似把进程退出码与进程退出信号输出到status中,以便父进程拿到子进程的退出信息。

那status是如何存储进程退出码与进程退出信号两个数据呢?

其实status是使用了32位比特位来存储,用status的后7位来存储终止信号,第8位存储core dump(后面讲),再往后8位存储的是进程退出信息,再往后尚未使用。

 测试代码:

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

void ChildRun()
{
    int *p = NULL;
    int cnt = 5;
    while(1)
    {
        printf("I am child process, pid: %d, ppid:%d, cnt: %d\n", getpid(), getppid(), cnt);
        sleep(1);
        cnt--;
        *p = 100;
    }
}

int main()
{
    printf("I am father, pid: %d, ppid:%d\n", getpid(), getppid());

    pid_t id = fork();
    if(id == 0)
    {
        // child
        ChildRun();
        printf("child quit ...\n");
        exit(123);
    }
    sleep(7);
    // father
    //pid_t rid = wait(NULL);
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if(rid > 0)
    {
        printf("wait success, rid: %d\n", rid);
    }
    else
    {
        printf("wait failed !\n");
    }
    sleep(3);
    printf("father quit, status: %d, child quit code : %d, child quit signal: %d\n", status, (status>>8)&0xFF, status & 0x7F);
}

运行结果

这个就是因为段错误,出现异常,进程异常退出!

进程的非阻塞式等待方式代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
	pid_t pid;
	pid = fork();
	if (pid < 0) {
		printf("%s fork error\n", __FUNCTION__);
		return 1;
	}
	else if (pid == 0) { //child
		printf("child is run, pid is : %d\n", getpid());
		sleep(5);
		exit(1);
	}
	else {
		int status = 0;
		pid_t ret = 0;
		do
		{
			ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待
			if (ret == 0) {
				printf("child is running\n");
			}
			sleep(1);
		} while (ret == 0);
		if (WIFEXITED(status) && ret == pid) {
			printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));
		}
		else {
			printf("wait child failed, return.\n");
			return 1;
		}
	}
	return 0;
}

执行结果! 

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

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

相关文章

什么是期货?期货的基础知识有哪些?

期货是一种标准化的远期合约&#xff0c;允许买卖双方在未来特定时间以预定价格交易货物或金融资产。也是一种金融衍生品&#xff0c;它为市场参与者提供了一种管理价格波动风险和进行投资的工具。 期货的基础知识有哪些 期货市场是一个复杂的金融环境&#xff0c;对于初学者来…

程序猿敲代码费脑掉头发?来看看铁打的便捷,Baidu Comate智能代码助手

前言&#xff1a;Baidu Comate 前世今生 Baidu Comate 安装教程 官网安装教程 手动安装教程 登录使用 插件功能初体验 代码生成指令板块 简易代码生成 代码解释 代码补充 代码注释 多种类智能问答&知识集调用 Paddle团队官方知识集 前言&#xff1…

设计模式(2)——工厂方法模式

目录 1. 摘要 2. 需求案例(设计一个咖啡店的点餐系统) 2.1 咖啡父类及其子类 2.2 咖啡店类与咖啡类的关系 3. 普通方法实线咖啡店点餐系统 3.1 定义Coffee父类 3.2 定义美式咖啡类继承Coffee类 3.3 定义拿铁咖啡继承Coffee类 3.4 定义咖啡店类 3.5 编写测试类 4. 简…

影响视频视觉质量的因素——各类视觉伪影

模糊效应&#xff08;Blurring Artifact&#xff09; 图像模糊&#xff08;blurring&#xff09;&#xff1a;平滑图像的细节和边缘产生的现象&#xff0c;模糊对于图像来说&#xff0c;是一个低通滤波器&#xff08;low-pass filter&#xff09;。一般而言&#xff0c;用户更…

VisualGDB:Linux静态库项目创建、编译及库的使用

接上篇《VisualGDB&#xff1a;Linux动态库项目创建、编译及库的使用》&#xff0c;静态库的创建和使用与动态库基本无差别&#xff0c;唯一需要做的就是指定项目生成静态库。 一、指定项目生成静态库 二、重新构建和编译项目 这里注意&#xff0c;同样要copy一个libxxx.so格式…

服务器数据恢复—RAID5磁盘阵列两块盘离线的数据恢复过程

服务器故障&#xff1a; 服务器中有一组由多块硬盘组建的raid5磁盘阵列&#xff0c;服务器阵列中2块硬盘先后掉线导致服务器崩溃。 服务器数据恢复过程&#xff1a; 1、将故障服务器中所有磁盘编号后取出&#xff0c;由硬件工程师对掉线的两块磁盘进行物理故障检测&#xff0c…

Linux 文件

文章目录 文件操作回顾(C/C)系统调用接口 管理文件认识一切皆文件C/C的文件操作函数与系统调用接口的关系……重定向与缓冲区 -- 认识重定向与缓冲区 -- 理解使用重定向缓冲区实现一个简单的Shell(加上重定向)标准输出和标准错误(在重定向下的意义) 磁盘文件磁盘存储文件操作系…

聊天框 - 微信加载历史数据的效果原来这样实现的

原文&#xff1a;https://juejin.cn/post/7337114587123335180?searchId20240509192958AF7D129567F92AD7E083 公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 前言 我记得2021年的时候做过聊天功能&#xff0c;那时业务也只限微信小程序 那时候的心路历程是&am…

win7开启远程桌面却连接不上,如何解决Win7系统开启远程桌面但无法连接的问题

在使用Win7系统时&#xff0c;有时候我们可能会遇到这样的问题&#xff1a;已经成功开启了远程桌面功能&#xff0c;但尝试连接时却总是失败。这可能是由于多种原因导致的&#xff0c;下面我们将详细分析并提供相应的解决方案。 确保本地网络连接正常 可以尝试通过Ping命令测试…

【start和run的区别(面试题)及创建线程的五种写法】

线程 1.start和run的区别2.创建线程的五种写法1.继承Thread,重写run2.实现runnable&#xff0c;重写run3.继承Thread,重写run,使用匿名内部类4.实现Runnable,重写run,使用匿名内部类5.使用lambda表达式 1.start和run的区别 1.start方法内部&#xff0c;是会调用到系统api&…

MATLAB 三维空间中在两点之间等间隔插入多个点 (67)

MATLAB 三维空间中在两点之间等间隔插入多个点 (67) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 用于加密直线点云,具体为根据给定的直线端点,沿着该直线方向,插入多个点,从而加密。具体方法和效果如下所示: 二、算法实现 1.代码 代码如下(示例): % 定…

融知财经:期货在哪里可以交易?期货交易有哪些交易规则?

作为当前金融市场的一种投资方式&#xff0c;期货只适合一些投资者&#xff0c;比如想获得高收益的投资者&#xff0c;因为期货的风险系数很高。但是很多投资者还不知道期货的意思&#xff0c;在一个固定的交易场所&#xff0c;期货是买卖标准化商品或金融资产的远期合约的交易…

SAP sq01,sq02,sq03创建query报表

步骤&#xff1a;1&#xff0c;SQ03创建用户组&#xff08;User Group&#xff09; 2&#xff0c;SQ02创建信息集&#xff08;InfoSet&#xff09; 3&#xff0c;SQ03分配用户和InfoSet 4&#xff0c;SQ01创建查询 5&#xff0c;SE93给Query分配Tcode 1&#xff0c;SQ03创建用…

pikachu靶场搭建(保姆级,手把手教学)

&#xff08;phpstudy安装pikachu配置&#xff09; 1.下载phpstudy&#xff08;以Windows系统为例&#xff09; 下载地址&#xff1a;https://www.xp.cn/download.html 1.打开网址 2.点击立即下载 3.选择适合自己的版本 查看自己电脑版本&#xff1a; 打开设置找到系统点击…

effective python学习笔记_函数

函数返回值尽量不要超过三个 局限性&#xff1a;当返回参数过多时&#xff0c;有时会搞混哪个是哪个&#xff0c;可能返回的两个值反了 解决方法&#xff1a;如果参数过多&#xff0c;可以组装*变量返回&#xff0c;或者自定义轻量类型或namedtuple返回 有意外情况时尽量抛异…

Kubernetes容器技术详解

kubernetes Kubernetes&#xff08;K8s&#xff09;由Google打造&#xff0c;是一款功能强大、灵活可扩展的容器编排平台&#xff0c;引领云原生技术潮流。 Kubernetes主要解决以下4大点&#xff1a; 1.自动化运维平台 如下图所示&#xff1a; Kubernetes携手Docker&#xf…

2024牛客五一集训派对day2 Groundhog Looking Dowdy 个人解题思路

前言&#xff1a; 被实验室教练要求要打的这次五一牛客的训练赛&#xff0c;这些区域赛难度的题对于大一的我来说难度实在是太高了&#xff0c;我和我的队友只写了一些非常简单的签到题&#xff0c;其他题目都没怎么看&#xff08;我们太弱了&#xff09;&#xff0c;但我可以分…

Powerdesigner导入mysql8之后注释丢失

目录 一、问题描述及解决思路 二、导入的步骤 1.先按正常步骤建立一个物理数据模型 &#xff08;1&#xff09;点击“文件-新建模型” &#xff08;2&#xff09;选择物理模型和数据库 2.从sql文件导入表 &#xff08;1&#xff09;点击“数据库-Update Model from Data…

智慧营销的未来:中国AIGC技术的演进与应用 #未来是现在的趋势#

&#x1f4d1;前言 随着人工智能&#xff08;AI&#xff09;技术的蓬勃发展&#xff0c;尤其是在营销技术&#xff08;MarTech&#xff09;领域&#xff0c;AIGC&#xff08;AI Generated Content&#xff09;技术在中国市场的应用和影响日益显著。2023年&#xff0c;中国在AIG…