Linux进程控制——Linux进程终止

前言:前面了解完前面的Linux进程基础概念后,我们算是解决了Linux进程中的一大麻烦,现在我们准备更深入的了解Linux进程——Linux进程控制!

我们主要介绍的Linux进程控制内容包括:进程终止,进程等待与替换,进程程序替换!


在这里插入图片描述


本篇主要内容:
重识进程创建
进程退出场景
错误码和退出码

在这里插入图片描述


进程终止

  • 1. 重识进程创建
    • 1.1 fork函数
    • 1.2 写时拷贝
    • 1.3 fork创建进程与进程终止
  • 2. 进程终止
    • 2.1 main的退出码
    • 2.2 C语言的错误码
    • 2.3 进程异常终止
  • 3. 总结拓展
    • 拓展:exit与_exit的区别
    • 总结


1. 重识进程创建

1.1 fork函数

在我们之前提到过,创建进程使用的是fork函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>

pid_t fork(void);

// 返回值:自进程中返回0,父进程返回子进程id,出错返回-1

进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度

fork函数返回值:

  • 子进程返回0,
  • 父进程返回的是子进程的pid

这些我们在之前都提到过,我们复习一下,今天我们重点要讲的是fork的写时拷贝


1.2 写时拷贝

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

当父进程形成子进程之后,子进程写入,发生写时拷贝,重新申请空间,进行拷贝,修改页表(OS)

但是,我们怎么知道发生了写时拷贝呢?写时拷贝的内容都是由操作系统来完成的

  • 其实父进程创建子进程的时候首先将自己的读写权限,改成只读,然后再创建子进程,此时是操作系统在做,用户并不知道,而且用户可能会对某一数据进行写入,这时页表转换就会出现问题,操作系统就会介入,就触发了我们重新申请内存拷贝内容的策略机制

1.3 fork创建进程与进程终止

接下来我们看一下这段代码:

  #include<stdio.h>
  #include<unistd.h>
  #include<stdlib.h>
  
  #define N 10
  
  typedef void (*callback_t)(); // 函数指针
   
  void Worker()
  {
     int cnt = 10;
     while(cnt)
     {
         printf("i am child process, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(),     cnt);
         sleep(1);
         cnt--;
     }
  }
 
  void createSubProcess(int n, callback_t cb)
  {
      
      int i = 0;
      for(i = 0; i < n; i++)
      {
          sleep(1);
          pid_t id = fork();
          if(id == 0)
          {
              printf("create child process success: %d\n", i);
              // child
              cb();                                                                      
              exit(0);
          }
      }
  }
  int main()
  {
      createSubProcess(N, Worker);
  
      // 只有父进程走到这里 
      sleep(100);
  
      return 0;
  }

而代码中的exit函数可以让进程终止
在这里插入图片描述

这段代码涵盖了fork创建进程与进程终止,让我们来执行以下

fork创建进程与进程的终止

下面将让我们真正来了解进程终止!


2. 进程终止

进程退出场景:

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

前面二者都是正常退出,而最后则是异常退出


2.1 main的退出码

我们之前写代码中,main函数只能return 0吗?答案是肯定不是!

在多进程环境中,我们创建子进程的目的就是协助父进程办事,但是父进程怎么知道子进程把事情办得怎么样?所以父进程要知道子进程办的怎么样,就有了退出码,而main函数的返回值,就是进程的退出码!

返回 0 就表示成功,其他数字就表示进程失败的原因,每个不同的数字代表不同的原因!

我们可以通过函数来直接查看每个数字代表的意义:strerror
在这里插入图片描述

它可以返回描述错误码的字符串

#include<stdio.h>
#include<string.h>

int main()
{
	for(int i = 0; i < 200; i++)
	{
		printf("%d: %s\n", i, strerror(i));
	}
	return 0;
}

在这里插入图片描述
退出码 0 正好对应的是成功!

在这里插入图片描述
当我们134位置处时,发现已经没有错误信息了。

注意:错误码我们可以自己自定义!


main函数的退出码是可以被父进程获取的,用来判断子进程的运行结果

我们可以直接用指令查看进程的退出码:
指令:echo $?

int main()
{
	return 31;
}

我们在执行完,这段代码后,再用指令查看退出码
在这里插入图片描述
我们可以发现指令:echo $?返回的是上一个进程的错误码


2.2 C语言的错误码

错误码和退出码:

  • 错误码通常是衡量一个库函数或者是一个系统调用一个函数的调用情况
  • 退出码通常是一个进程退出的时候,他的退出结果
  • 二者都是当失败的时候,用来衡量函数、进程出错是的出错详细原因

我们用代码来测试一下:

#include<stdio.h>
#include<errno.h>

int main()
 {
 	// errno 可以返回最近一次错误的错误码
    int ret = 0;
    printf("before: %d\n", errno);
    FILE *fp = fopen("csdn.txt", "r");
    if(fp == NULL)
    {
       printf("after: %d, error string: %s\n", errno, strerror(errno));                                                                                                               
       ret = errno;
    }
    return ret;
 }

在这里插入图片描述

在这里插入图片描述
一旦出现错误,错误码errno就会被系统自动赋值

可以通过错误码来判断代码运行的情况


2.3 进程异常终止

当我们的代码出异常了,也就是进程异常终止了,退出码还有意义吗?

// 当我们在运行这样的代码时

int a = 100;
a /= 0;
......
int *p = NULL;
*p = 100;
......

第一种情况: Floating point exception
第二种情况: Segmentation fault

当然不止这两个情况,但是它们都会让程序进程异常终止!

其实一旦程序出现了异常,操作系统就是通过信号的方式来杀掉这个进程!
在这里插入图片描述
而我们的前面两种情况正好对应了kill -8kill -11

我们来试试,通过使用信号能不能还原之前这几种错误情况

while(1)
{
	printf("i am a process, pid: %d\n", getpid());
	sleep(1);
}

通过信号终止进程

进程出异常本质是收到了对应的信号,因此一个进程是否出异常,我们只要看有没有收到信号即可


3. 总结拓展

拓展:exit与_exit的区别

在之前讲到正常退出时,我们有3种情况。

正常终止

    1. 从main返回
    1. 调用exit
    1. _exit

而exit与_exit两个有什么区别和联系呢?
在这里插入图片描述
在这里插入图片描述

首先他们二者都可以让进程终止,并且使用方法也一样,那他们到底有什么区别呢?我们用代码来一探究竟!

//代码一:
int main()
{
	printf("Hello");
	exit(0); 
}

......
//代码二:
int main()
{
	printf("Hello");
    _exit(0); 
}

代码一:
在这里插入图片描述
代码二:
在这里插入图片描述
为什么会出现这种情况呢?

exit最后也会调用exit, 但在调用exit之前,还做了其他工作:

    1. 执行用户通过 atexit或on_exit定义的清理函数。
    1. 关闭所有打开的流,所有的缓存数据均被写入
    1. 调用_exit

在这里插入图片描述

printf打印如果不使用\n换行的话,数据会被存储到缓冲区里,,exit函数会帮助我们
刷新缓冲区的数据,然而_exit函数不会。因为exit函数在调用exit之前将所有缓存数据都写入了,所以在终止进程时,会将数据打印在屏幕上!


总结

进程终止相对于其他的进程控制来说,是很好理解的。我们主要介绍了进程终止,在明白错误码和退出码之后,相信能理解父进程是怎么得到子进程信息的。让我们期待下一节——进程等待与替换!

谢谢大家支持本篇到这里就结束了
在这里插入图片描述

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

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

相关文章

GoF之代理模式(静态代理+动态代理(JDK动态代理+CGLIB动态代理带有一步一步详细步骤))

1. GoF之代理模式&#xff08;静态代理动态代理(JDK动态代理CGLIB动态代理带有一步一步详细步骤)&#xff09; 文章目录 1. GoF之代理模式&#xff08;静态代理动态代理(JDK动态代理CGLIB动态代理带有一步一步详细步骤)&#xff09;每博一文案2. 代理模式的理解3. 静态代理4. 动…

函数式接口-闭包与柯里化

闭包 定义 示例 注意 这个外部变量 x 必须是effective final 你可以生命他是final&#xff0c;你不声明也会默认他是final的&#xff0c;并且具有final的特性&#xff0c;不可变一旦x可变&#xff0c;他就不是final&#xff0c;就无法形成闭包&#xff0c;也无法与函数对象一…

单链表经典算法OJ题---力扣206,876(带图详解

1.链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;【点击即可跳转】 思路&#xff1a;创建三个指针&#xff0c;看下图 注意&#xff1a;n3如果为空&#xff0c;则不能继续指向下一节点&#xff0c;需要进行判断 代码实现&#xff1a; struct ListNode* reverseLi…

手游掘金最新玩法,单条视频变现1w+,一部手机即可操作,保姆级教程

如果你也想通过手机赚钱&#xff0c;在这里有一个非常好的项目&#xff0c;它可以让你轻松赚到额外的收入。 这个手游掘金最新玩法&#xff0c;是一个非常受欢迎的项目&#xff0c;它可以让你通过制作单条视频来获得高额收益。不同于传统的游戏赚钱方式&#xff0c;这个方法不…

树莓派安装opencv

安装opencv 上述步骤完成后&#xff0c;输入以下代码(基于python3) sudo apt-get install python3-opencv -y不行的话&#xff0c;试试换源&#xff0c;然后 sudo apt-get update成功&#xff01; 测试opencv是否安装成功 输入 python3 然后再输入 import cv2 没有报错就…

闲来装个虚拟机Ubuntu24.04和硬盘分区及挂载

简述 最近ubuntu出新版本了&#xff0c;ubuntu24.04&#xff0c; 俗称高贵食蚁兽。5年前进行Android或者linux开发基本是在windows下的虚拟机中进行。目前&#xff0c;虽然物质基础提高了&#xff0c;功能有独立进行编译、代码管理的服务器了。可以通过ssh登录&#xff0c;但是…

[Bug]:由于中国防火墙,无法连接 huggingface.co

问题描述 : OSError: We couldnt connect to https://huggingface.co to load this file, couldnt find it in the cached files and it looks like youscan/ukr-roberta-base is not the path to a directory containing a file named config. Json. Checkout your internet …

【数据结构】排序(一)—— 希尔排序(思路演进版)

目录 一、常见的排序算法分类 二、常见排序算法的实现 2.1插入排序 2.1.1基本思想 2.1.2直接插入排序 思路 step1.单趟控制 step2.总体控制 代码实现 测试 特性总结 2.1.3 希尔排序( 缩小增量排序 ) 基本思想 思路演进 &#x1f308;1.代码实现单组排序&#…

GD32用ST-Link出现internal command error的原因及解决方法

一、GD32 F407烧录时出现can not reset target shutting down debug session 搜寻网上资料&#xff0c;发现解决方式多种多样&#xff0c;做一个简单的总结&#xff1a; 1.工程路径包含中文名 2.需更改debug选项 3.引脚冲突 4.杜邦线太长 而先前我的工程路径包含中文名也仍…

Java Array 数组

文章目录 Java Array 数组一&#xff0c;数组的介绍1. 数组的理解(Array)2. 数组相关的概念3. 数组的特点:4. 变量按照数据类型的分类5. 数组的分类6. 一维数组的使用(6个基本点)7. 数组元素的默认初始化值的情况 二&#xff0c;一维数组1. 一维数组功能测试2. 一维数组案例(1)…

香港虚拟主机哪里可以试用?用于企业建站的

香港虚拟主机适合个人、企业建站&#xff0c;包括外贸企业网站、个人博客网站、中小企业官网等&#xff0c;那么作为新手不知道哪家香港虚拟主机好用的时候&#xff0c;该如何找到可以试用的香港虚拟主机呢&#xff1f; 香港虚拟主机也称作香港空间、香港虚拟空间&#xff0c;…

深入探索Android应用数据共享之ContentProvider

本文将深入探讨Android开发中非常重要的数据共享机制 - ContentProvider。 主要内容包括: ContentProvider的基本定义及特点如何实现一个自定义的ContentProviderContentProvider对外提供的功能以及对外部应用的权限控制对ContentProvider的一些常见使用场景使用ContentProvi…

linux_用户与组

用户与组 基于账号的访问控制 账号类型&#xff1a;用户账号(UID) 、组账号(GID) 用户账号简介 作用: 1.可以登陆操作系统 2.不同的用户具备不同的权限 唯一标识&#xff1a;UID&#xff08;编号从0开始的编号&#xff0c;默认最大60000&#xff09; 管理员root的UID&…

简单贪吃蛇的实现

贪吃蛇的实现是再windows控制台上实现的&#xff0c;需要win32 API的知识 Win32 API-CSDN博客https://blog.csdn.net/bkmoo/article/details/138698452?spm1001.2014.3001.5501 游戏说明 ●地图的构建 ●蛇身的移动&#xff08;使用↑ . ↓ . ← . → 分别控制蛇的移动&am…

哈希(构造哈希函数)

哈希 哈希也可以叫散列 画一个哈希表 哈希冲突越多&#xff0c;哈希表效率越低。 闭散列开放定址法: 1.线性探测&#xff0c;依次往后去找下一个空位置。 2.二次探测&#xff0c;按2次方往后找空位置。 #pragma once #include<vector> #include<iostream> #i…

基于SpringBoot+Vue的物流管理系统

运行截图 获取方式 Gitee仓库

机器学习(五) ----------决策树算法

目录 1 核心思想 2 决策树算法主要步骤 3 决策树算法的分类 3.1 ID3算法&#xff08;Iterative Dichotomiser 3&#xff09;&#xff1a; 3.1.1 基本步骤 3.1.2 原理 信息增益 3.1.3 注意事项 3.2 C4.5算法&#xff1a; 3.2.1. 信息增益率 计算公式 3.2.2. 构建决策…

Rpcx (一):详解【介绍、基础示例 demo】

一.rpcx介绍 1.1 rpc是什么 远程过程调用的通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。简单地说就是能使应用像调用本地…

服装店会员管理系统结合小程序商城帮你挖掘出潜在客户

在现代社会&#xff0c;随着科技的不断进步和人们消费习惯的变化&#xff0c;传统的服装店已经不再能够满足消费者的需求。为了更好地服务客户&#xff0c;提升销售业绩&#xff0c;许多服装店开始引入会员管理系统&#xff0c;并结合小程序商城&#xff0c;实现线上线下的无缝…

【半夜学习MySQL】表的约束(含主键、唯一键、外键、zerofill、列描述、默认值、空属性详解)

&#x1f3e0;关于专栏&#xff1a;半夜学习MySQL专栏用于记录MySQL数据相关内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 前言空属性默认值列描述zerofill主键主键概述主键删除与追加复合主键 自增长唯一键外键综合案例 前言 上一篇文章中介绍了数…