探索Linux中的进程控制:从启动到退出的背后原理

个人主页:chian-ocean

文章专栏-Linux

前言:

进程控制是操作系统对进程的创建、运行、调度、中止等活动进行管理和协调的行为。它是操作系统中至关重要的一部分,保证多任务处理环境下的资源分配和系统稳定性。

在这里插入图片描述

进程创建

fork( )

  • fork() 调用后:

    • 子进程是父进程的副本,拥有相同的代码和数据。
    • 子进程的所有资源(如内存、打开的文件描述符)最初与父进程共享,但在写入数据时会触发**写时复制(Copy-on-Write,COW)**机制。

    返回值:

    • **在父进程中:**返回子进程的 PID(进程 ID)。
    • **在子进程中:**返回 0
    • **如果失败:**返回 -1 并设置错误码(通常是因为系统资源不足)
int main()
{pid_t id = fork();if(id > 0){while(1){cout << "父进程"<< "pid :"<<getpid() <<endl; sleep(2);}      }else if(id == 0){while(1){   cout << "子进程"<<endl;sleep(2);                     }}else {perror("fork");cout << "子进程"<< "pid :"<<getpid() <<endl;sleep(2);}}else {perror("fork");}return 0;
}

执行代码

在这里插入图片描述

进程退出(终止)

进程终止是操作系统中一个进程完成任务或由于某种原因被终止运行的过程。在进程终止后,操作系统会释放该进程占用的资源,并将其从系统中的进程表中移除

退出码

退出码是进程在退出时返回给操作系统或父进程的一个状态值,表示进程的退出状态。退出码常用于判断进程是否成功完成任务或发生了错误

成功退出:

  • 退出码为 0,表示进程正常结束,没有错误。
  • 这也就是为什么默认return 0

失败退出:

  • 0 值通常表示进程发生了错误或异常。
  • 不同的退出码可以表示不同的错误原因(由程序员定义)。

检查退出码

#终端检查
echo $?

demo

  • 在这里面设置退出码为 8 ,以便观察。
#include <iostream>    
#include <unistd.h>    
#include <stdlib.h>    using namespace std;    int main()    
{    int i = 10;    while(i--)    {    cout << i <<" ";    }    cout << endl;    return 8;    
}

执行

在这里插入图片描述

进程退出的方式

  • **正常退出:**主函数执行到最后,正常返回。
  • **异常退出:**发生异常(如段错误、非法访问内存、除以零)导致进程被操作系统终止。

正常退出

主函数返回:

  • 主函数(main())返回值即为进程的退出码。

调用 exit() 函数:

  • 显式终止进程,返回退出码。
  • 执行清理操作(如刷新缓冲区、关闭文件等)。
#include <iostream>      
#include <unistd.h>      
#include <stdlib.h>      using namespace std;      int func()      
{               cout << "调用func"<<endl;      exit(1);      return 1;      
}               int main()      
{                                                                                                                                   int funcret = func();      cout << funcret << endl;      return 0;                     
} 

代码功能说明

  1. func 函数
    • 输出一条消息:调用func
    • 调用 exit(1) 直接终止程序,返回退出码 1
    • 后面的 return 1 永远不会被执行,因为 exit(1) 会导致程序立即退出。
  2. main 函数
    • 调用 func()
    • 由于 func() 中调用了 exit(1),程序会立即退出,func 返回值永远不会被赋给 funcret
    • main 中的 cout << funcret << endl;return 0; 永远不会被执行。

在这里插入图片描述

_exit和exit

**_exit()不会执行任何用户态的清理工作,直接终止进程,不会:

  1. 调用 atexit() 注册的清理函数。
  2. 刷新标准 I/O 流。
  3. 关闭打开的文件缓冲区。
#include <iostream>
#include <unistd.h>
using namespace std;
int main()    
{    cout << "This is exit"<< endl;    cout << "This will not be flushed.";  // 没有换行符,缓冲区未刷新    exit(0);  // 直接终止程序,刷新缓冲区  cout << "This is _exit"<< endl;    cout << "This will not be flushed.";  // 没有换行符,缓冲区未刷新    _exit(0);  // 直接终止程序,不刷新缓冲区                                                    return 0;    
}

cout << "This is exit << endl;":

  • 输出 "This is exit" 并刷新缓冲区。
  • 输出立即显示在屏幕上。

cout << "This will not be flushed.";:

  • 输出内容存储在缓冲区中,但未刷新(没有换行符)。

_exit(0);:

  • 程序立即终止,不刷新缓冲区。
  • "This will not be flushed." 不会被输出,因为缓冲区未刷新。

在这里插入图片描述

returnexit()_exit() 总结对比表

特性/行为returnexit()_exit()
作用范围退出当前函数,返回控制权给调用者终止整个程序,返回控制权给操作系统立即终止当前进程,不返回控制权
适用范围函数正常结束,返回值给调用者程序正常或错误退出,需要完成清理工作子进程退出或紧急情况下立即终止程序
I/O 缓冲区刷新自动刷新(如果退出程序)刷新所有标准 I/O 缓冲区不刷新标准 I/O 缓冲区
atexit() 注册函数不调用调用所有通过 atexit() 注册的清理函数不调用
局部变量析构调用局部变量的析构函数(C++ 对象)不调用析构函数不调用析构函数
性能性能高,适用于正常函数返回较慢,涉及缓冲区刷新和清理操作性能最高,直接调用系统内核
适用场景函数正常结束,逻辑返回值给调用者程序终止,需要完成缓冲区刷新和清理工作子进程退出或需要立即终止进程时
调用位置仅在当前函数中有效可在程序任意位置调用可在程序任意位置调用

异常退出

异常终止的表现

非零退出码:表示异常终止的原因。

#include<iostream>
using namespace std;
int main()
{int a = 10, b = 0;int c = a / b;  // 除以零导致异常终止cout << c << endl;
}

执行代码

在这里插入图片描述

常见退出码:

退出码原因
139段错误(SIGSEGV)。
136浮点异常(SIGFPE)。
1一般错误。
6调用 abort()SIGABRT)。
9强制终止(SIGKILL
# 查看错误信号
kill -l

在这里插入图片描述

错误码

打印错误码

#include <iostream>    
#include <cerrno>    
#include <cstring>        
using namespace std;        
int main()    
{    for(int i = 0; i < 135; i++)    {    const char * errmessage = strerror(i);    if(errmessage)    {    cout<< "code error" <<" "<< i <<":"<< errmessage <<endl;     }    }    return 0;       
}

执行代码

在这里插入图片描述

  • 可以观察到默认0编码是success
  • 这里面只显示一部分
  1. 标准错误码:
    • 通常范围是 1 到 134,其中每个错误码都由 POSIX 标准定义,常见于 errno.h
  2. 系统特定错误码:
    • 某些错误码可能特定于操作系统,错误描述可能不同。

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

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

相关文章

密码无关认证:金融机构如何解决密码问题

密码安全问题&#xff0c;依然是金融行业面临的重大挑战。尽管密码简单易用&#xff0c;但许多金融机构仍然依赖这种方式进行身份认证。幸运的是&#xff0c;随着技术的发展&#xff0c;密码无关认证已经成为一种更加安全、便捷的选择&#xff0c;它能够为数字银行带来更好的用…

HarmonyOS基于ArkTS卡片服务

卡片服务 前言 Form Kit&#xff08;卡片开发框架&#xff09;提供了一种在桌面、锁屏等系统入口嵌入显示应用信息的开发框架和API&#xff0c;可以将应用内用户关注的重要信息或常用操作抽取到服务卡片&#xff08;以下简称“卡片”&#xff09;上&#xff0c;通过将卡片添加…

Django 多环境配置实战指南

在现代 Web 开发中,一个项目通常需要在多个环境中运行,例如开发环境、测试环境和生产环境。每个环境的配置可能不同,比如数据库连接、调试模式、密钥等。为了确保项目在不同环境中的灵活性和安全性,我们需要合理地管理多环境配置。 本文将详细介绍如何在 Django 项目中实现…

运算放大器应用电路设计笔记(六)

6.1输出失调电压发生的原因与计算 6.1.1用噪声增益进行评价 若运算放大器两个输入端接地&#xff0c;则理想运放输出为零&#xff0c;但实际的运放输出不为零&#xff0c;有一定的直流输出电压。这种直流电压称为输出失调电压。发生的原因是&#xff0c;运算放大器内部元件尤…

【Vim Masterclass 笔记25】S10L45:Vim 多窗口的常用操作方法及相关注意事项

文章目录 S10L45 Working with Multiple Windows1 水平分割窗口2 在水平分割的新窗口中显示其它文件内容3 垂直分割窗口4 窗口的关闭5 在同一窗口水平拆分出多个窗口6 关闭其余窗口7 让四个文件呈田字形排列8 光标在多窗口中的定位9 调节子窗口的尺寸大小10 变换子窗口的位置11…

【算法】经典博弈论问题——巴什博弈 python

目录 前言巴什博弈(Bash Game)小试牛刀PN分析实战检验总结 前言 博弈类问题大致分为&#xff1a; 公平组合游戏、非公平组合游戏&#xff08;绝大多数的棋类游戏&#xff09;和 反常游戏 巴什博弈(Bash Game) 一共有n颗石子&#xff0c;两个人轮流拿&#xff0c;每次可以拿1~m颗…

电脑如何访问手机文件?

手机和电脑已经深深融入了我们的日常生活&#xff0c;无时无刻不在为我们提供服务。除了电脑远程操控电脑外&#xff0c;我们还可以在电脑上轻松地访问Android或iPhone手机上的文件。那么&#xff0c;如何使用电脑远程访问手机上的文件呢&#xff1f; 如何使用电脑访问手机文件…

【设计模式-行为型】状态模式

一、什么是状态模式 什么是状态模式呢&#xff0c;这里我举一个例子来说明&#xff0c;在自动挡汽车中&#xff0c;挡位的切换是根据驾驶条件&#xff08;如车速、油门踏板位置、刹车状态等&#xff09;自动完成的。这种自动切换挡位的过程可以很好地用状态模式来描述。状态模式…

CTF随题思路—简单的base编码

打开是一大段base64编码&#xff0c;多次解码后再用base92解码

顺序表和链表(详解)

线性表 线性表&#xff08; linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。…

C# 解析 HTML 实战指南

在网页开发和数据处理的场景中&#xff0c;经常需要从 HTML 文档里提取有用的信息。C# 作为一门强大的编程语言&#xff0c;提供了丰富的工具和库来实现 HTML 的解析。这篇博客就带你深入了解如何使用 C# 高效地解析 HTML。 一、为什么要在 C# 中解析 HTML 在实际项目中&…

Spring 是如何解决循环依赖问题

Spring 框架通过 三级缓存 机制来解决循环依赖问题。循环依赖是指两个或多个 Bean 相互依赖&#xff0c;形成一个闭环&#xff0c;例如 Bean A 依赖 Bean B&#xff0c;而 Bean B 又依赖 Bean A。Spring 通过提前暴露未完全初始化的 Bean 来解决这个问题。 以下是 Spring 解决…

vxe-table和element表尾合计行

1、vxe-table vxe-table的表尾合计&#xff0c;需要show-footer和footer-method搭配使用。 <vxe-table:data"tableData"ref"vxeRef"border resizable :footer-method"footerMethod":show-footer"true" >…

监控与调试:性能优化的利器 — ShardingSphere

在分布式数据库系统中&#xff0c;监控和调试是确保系统高效运行的关键。ShardingSphere 提供了多种监控和调试工具&#xff0c;帮助开发者实时跟踪和优化性能&#xff0c;识别瓶颈&#xff0c;进行故障排查&#xff0c;从而提升系统的稳定性和响应速度。本文将介绍如何使用 Sh…

上位机知识篇---ROS2命令行命令静态链接库动态链接库

文章目录 前言第一部分&#xff1a;ROS2命令行命令1. 基础命令&#xff08;1&#xff09;ros2 run&#xff08;2&#xff09;ros2 launch&#xff08;3&#xff09;ros2 node&#xff08;4&#xff09;ros2 topic&#xff08;5&#xff09;ros2 service&#xff08;6&#xff0…

Browser-Use WebUI项目启动指南

摘要 此前发布《Browser - Use WebUI 使用体验》博文后&#xff0c;鉴于部分朋友运行时出现问题&#xff0c;重新运行并整理相关内容。本文详细记录 Web UI 项目启动全过程&#xff0c;涵盖 Python 3.11、Chrome 浏览器及 API Keys 等环境要求&#xff0c;Python 环境检查、依赖…

leetcode 面试经典 150 题:有效的括号

链接有效的括号题序号20题型字符串解法栈难度简单熟练度✅✅✅ 题目 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须…

Grafana系列之Dashboard:新增仪表板、新增变量、过滤变量、变量查询、导入仪表板、变量联动、Grafana Alert

概述 关于Prometheus和Grafana的安装&#xff0c;略过。 写在前面 Dashboard&#xff1a;仪表板&#xff0c;可包含多个PanelPanel&#xff1a;面板&#xff0c;Dashboard中的组件 如有写得不对的地方&#xff0c;烦请指出。 新增仪表板 点击右上角的 选择New dashboard…

使用 Ansys Discovery 对离心风机进行仿真

了解设置模拟并获得有用结果的步骤。 离心风机&#xff1a;基础知识和重要性 离心风机&#xff0c;也称为径流式风机&#xff0c;是旨在通过将动能转化为势能来增加空气或气体的压力和流量的机械装置。它们的工作原理是利用旋转叶轮产生的离心力轴向吸入空气&#xff0c;然后…

客户案例:向导ERP与金蝶云星空集成方案

一、客户背景 该客户公司主要致力于黄金、铂金、金镶玉首饰的研发设计、生产加工、批发及直营加盟业务。公司总部占地面积目前已达6000多平方米&#xff0c;拥有标准生产厂房和现代化生产设施&#xff0c;拥有一支完善的企业管理团队和专业技工队伍。 该企业目前同时采用向导 E…