进程控制(一)进程创建与终止

文章目录

  • 进程创建
    • 又识fork函数
    • fork函数返回值
    • 写时拷贝
    • fork常规用法
    • fork调用失败的原因
  • 进程终止
    • 进程退出的三种场景
    • 进程常见退出方法
      • main函数return 0
      • 使用exit函数
      • 使用_exit函数
    • 异常退出

进程创建

又识fork函数

目前我们知道在Linux下创建进程有两种方式:

  1. 命令行启动命令(自己写的程序、指令…)
  2. fork()函数

我们知道在linux中fork函数是非常重要的函数,它从一个已经存在进程中创建一个新进程。新进程为子进程,而原来的进程为父进程。

在这里插入图片描述
进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度
创建子进程的进程控制块task_struct;
创建子进程的进程地址空间mm_struct;
重新申请空间,进行拷贝,修改页表;
#include<stdio.h>
#include<unistd.h>int main()
{printf("Before:PID is %d\n", getpid());pid_t id = fork();if(id == -1){printf("fork error!!\n");}printf("After : PID is %d, fork return is %d\n", getgid(), id);                                                                                                           sleep(1);return 0;
}

在这里插入图片描述

调用fork函数之前,Before输出一次,由父进程输出;
调用fork函数之后,After输出两次,由父、子进程分别输出一次。
所以fork之前父进程单独执行,fork之后,父子两个进程分别执行。且fork之后,谁先执行不确定,由调度器自行决定。

fork函数返回值

#include <unistd.h>
pid_t fork(void);
返回值:子进程返回0,父进程返回子进程pid,出错返回-1

写时拷贝

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。

在这里插入图片描述

  • 为什么数据要进行写时拷贝?
    使父、子进程之间是相互独立的;
    节省内存和系统资源,提高 fork 的效率,减少 fork 失败的概率。
  • 为什么不一开始就复制出来一份给子进程?
    所有的数据,父、子进程并不是都要进行写入的,有的仅仅需要读取,而此时拷贝是没有意义的,而且还会浪费内存资源。

fork常规用法

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

fork调用失败的原因

  • 系统中有太多的进程
  • 实际用户的进程数超过了限制

进程终止

进程退出的三种场景

进程退出只有三种情况:

  1. 代码运行完毕,结果正确。
  2. 代码运行完毕,结果不正确。
  3. 代码异常终止。

进程常见退出方法

main函数return 0

我们之前在写C\C++代码的时候,总会在main函数的结尾写上一个return 0但这是为什么呢??
首先我们需要明确知道,不一定非要return 0,也可以return其他值。

  1. main函数执行到return 语句时,表示该进程执行完毕;
  2. 其余函数执行到return 语句时,表示该函数执行完毕;
  3. 程序正常执行完毕并且结果正确时返回0;
  4. 程序正常执行完毕但结果不正确时返回!0;

那么程序既然正常执行完毕,但结果不正确时,会返回什么!=0,那就是1 2 3 4 5,那么他们又有什么含义,我们看下面的一段代码
在这里插入图片描述

在这里插入图片描述
看来0代表的就是success, 并且在134号以后就是unknown error

在这里插入图片描述


查看最近进程的退出码:
指令:echo $?

在这里插入图片描述

在这里插入图片描述
第一次返回100是我们所写的进程返回值;
第二次返回0是我们第一次使用echo $?成功的返回值;

使用exit函数

该函数使用时需要包头文件#include<stdlib.h>有一个int类型的参数,其含义是错误码,和main函数的return值是一个意思
在这里插入图片描述
但exit函数和return是有一定的区别的

  • exit用于结束正在运行的整个程序,它将参数返回给操作系统,把控制权交给操作系统;而return 是退出当前函数,返回函数值,把控制权交给调用函数;
  • exit是系统调用函数,表示一个进程的结束;return 是语言级别的,表示调用堆栈的返回;
  • exit函数在程序任一地方使用都可以直接退出程序,并且返回错误码
    任意地点调用exit函数,表示进程退出,不进行后续操作

使用_exit函数

在这里插入图片描述

它和exit一样都是终止进程,并且参数都一样含义也一样但差别在哪??

我们观察下面的运行结果


在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述
OK了,我们好像发现了其中的奥秘
第一个打印出来了,而第二个没有打印。


对于printf函数,我们要么碰到\n刷新条件、要么手动fflush刷新、要么终止进程(main函数中的return 也可以做到)即将结束自己刷新。
对于printf函数来说,如果没有换行\n的话,那么其先会保存在缓冲区中,但我们使用exit函数的话退出进程时却被打印出来了,也就是说exit函数会对缓冲区进行刷新,而_exit函数并没有使其打印出来也就是说没有这个功能。
既然exit函数是C的库函数,而_exit函数是系统调用函数,那么我们不妨大胆猜想,缓冲区是由C来维护的

总结

  1. exit是库函数、_exit是系统调用函数
  2. exit终止进程的时候会自动刷新缓冲区、_exit终止进程时,不回刷新缓冲区

异常退出

数组越界
野指针访问

此时运行程序后,程序会退出。这时候再去使用指令: echo $?就没有意义了!
就好比考试作弊后,无论你100,20分结果都是一样的。没有意义!

全局变量errno
在这里插入图片描述
用于显示错误信息的字符串。当程序运行时,errno宏被设置为0,一旦程序发生了系统级的错误,errno宏就会被设置为其它值。


perror函数
在这里插入图片描述
函数用于打印最近的库函数执行出错的消息

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>int main() 
{FILE *file = fopen("non_existent_file.txt", "r");if (file == NULL) {// errno 现在已被 fopen 设置,描述错误的原因perror("Error opening file"); // 打印 "Error opening file: <系统的错误消息>"return EXIT_FAILURE;}// 正常处理文件fclose(file);return EXIT_SUCCESS;
}

输出

Error opening file: No such file or directory

尝试打开一个不存在的文件,由于文件不存在,fopen() 将返回 NULL 并设置全局变量 errno。然后我们调用 perror() 来打印错误消息,该消息将包括由 errno 表示的特定错误原因。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot网上书城交易平台源码和论文

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括网上书城管理系统的网络应用&#xff0c;在国外网上书城管理系统已经是很普遍的方式&#xff0c;不过国内的书城管理系统可能还处于起步阶段。网上书城管理系统具有网上书城信…

套接字小结

步骤&#xff1a; 1、定义sockaddr_in结构体 并对里面的成员进行初始化 sin_family IPV4还是IPV6 sin_port 端口号 hton: host to net //主机 -> 网络 小端转大端 struct sockaddr_in server_addr , client_addr;//对服务端网络信息结构体进行初始化server_add…

招聘网站简单爬虫_24.1.26

完整程序传送门 24.1.26 前些天接了一个大两届的师兄的小活&#xff0c;做了一下爬boss直聘岗位信息的程序&#xff0c;在这里记录一下 程序框架 定义一个名为paQu的接口函数&#xff0c;用于检查窗口的输入&#xff0c;它接受一个参数self&#xff0c;获取self对象的a属性&am…

第九节HarmonyOS 常用基础组件13-TimePicker

1、描述 时间选择组件&#xff0c;根据指定参数创建选择器&#xff0c;支持选择小时以及分钟。默认以24小时的时间区间创建滑动选择器。 2、接口 TimePicker(options?: {selected?: Date}) 3、参数 selected - Date - 设置选中项的时间。默认是系统当前的时间。 4、属性…

【驱动】TI AM437x(内核调试-07):devmem2直接读写内存、寄存器,devkmem读取内核变量

1、/dev/mem 和 /dev/kmem 1)/dev/mem: 物理内存的全镜像。可以用来访问物理内存 2)/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。kernel部分内存用户空间本不可访问。但是因为所有进程共享内核空间的页表。所以内核虚拟地址对应物理地址是确定的…

python_ACM模式《剑指offer刷题》链表3

题目&#xff1a; 注意&#xff1a; 剑指offer上对这道题目的描述是给定的删除节点是节点指针。这表明这道题可以用时间复杂度为O(1)的方式解决。 而leetcode上对类似本题的描述是&#xff1a; 给定删除节点是节点值&#xff0c;这决定了本题时间复杂度必然至少为O(N)。因为…

写在28岁,回看3年前“啃老”的自己,庆幸当时入了软件测试这行

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 为什么会学习软件测试&#xff1f; 已经28岁了&#xff0c;算一下快过去3年了&#xff0c;刚…

SpringBoot 实现自定义指标监控

一、添加业务监控指标 在 spring-web-prometheus-demo 项目的基础上&#xff0c;我们添加一个 PrometheusCustomMonitor 类。在这里面我们定义了三个业务指标&#xff1a; order_request_count&#xff1a;下单总次数order_amount_sum&#xff1a;下单总金额 Component publ…

Element ui 的组件弹窗 el-dialog点击的时候全屏变灰问题解决

最近在使用Element UI 的弹窗组件的时候发现这个组件各种的应用都没有问题&#xff0c;数据和元素的应用都是正确的但是在点击显示这个弹窗的时候全屏幕都会变灰。 这也不是因为增加了modal 遮挡幕的问题&#xff0c;在经过不断的排查代码的时候基本排除了代码的问题&#xf…

电路笔记 :MOS场效应晶体管+红外遥控+AMS1117 电源模块

三极管&#xff08;BJT&#xff0c;Bipolar Junction Transistor&#xff09;和 MOSFET&#xff08;Metal-Oxide-Semiconductor Field-Effect Transistor&#xff09;是两种不同类型的晶体管&#xff0c;它们在工作原理、性能特性和应用方面有一些重要的区别。 结构和工作原理…

fastapi报错

初始化报错&#xff0c;非常低级错&#xff0c;扇自己10八张 app FastApi()

HCIA-HarmonyOS设备开发认证-2.设备开发入门

目录 HarmonyOS设备开发学习路径一、开发项目与工具介绍1.1、设备开发环境准备1.2、设备开发流程1.3、Huawei DevEco Device Tool 二、OpenHarmony介绍OpenHarmony目录结构详细介绍applications目录详解base目录详解foundation目录详解 OpenHarmony接口分层介绍CMSIS 和 POSIX …