【Linux】进程管理:从理论到实践(一)

news2024/9/27 9:19:05

🌈 个人主页:Zfox_
🔥 系列专栏:Linux

目录

  • 一: 🔥 进程的基本概念
  • 二: 🔥 描述进程-PCB
  • 三: 🔥 查看进程
    • 🥝 通过系统目录
    • 🥝 通过ps命令
  • 四: 🔥 创建进程-fork() 📚
  • 五: 🔥 进程状态
    • 🥝 进程状态查看
    • 🍊 进程状态转化
  • 六: 🔥 共勉

一: 🔥 进程的基本概念

  • 在给进程下定义之前,我们先了解一下进程:

💦 我们在编写完代码并运行起来时,在我们的磁盘中会形成一个可执行文件,当我们双击这个可执行文件时(程序时),这个程序会加载到内存中,而这个时候我们不能把它叫做程序了,应该叫做进程。

💦 所以说,只要把程序(运行起来)加载到内存中,就称之为进程。
💦 进程的概念:程序的一个执行实例,正在执行的程序等。
💦 如果站在内核的角度来看:进程是分配系统资源的单位。

二: 🔥 描述进程-PCB

🍊 一个概念需要一个具体的结构体来进行描述的。进程中的信息就被放在了一个叫做进程控制块(PCB)的结构体中。

  • PCB:进程控制块(结构体)

当一个程序加载到内存中,操作系统要为刚刚加载到内存的程序创建一个结构体(PCB),进程信息被放在这个结构体中(PCB),可以理解为PCB是进程的属性的集合。

在Linux操作系统下的PCB是: task_struct
🍊 task_struct 是Linux内核的一种数据结构,它会被装载到 RAM(内存) 里并且包含着进程的信息,在进程执行时,任意时间内,进程对应的 PCB 都要包含以下内容:

  • 标示符:描述本进程的唯一标示符,用来区别其他进程
  • 状态:任务状态
  • 优先级:相对于其他进程的优先级
  • 程序计数器:程序中即将被执行的下一条指令的地址
  • 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块指针
  • 上下文数据:进程执行时处理器的寄存器中的数据
  • I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的- - - 文件列表
  • 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
  • 其他信息:…

三: 🔥 查看进程

🥝 通过系统目录

🍊 第一种方式:在 /proc 这个目录下保存着所有进程的信息。
⚡ 注意:/proc不是磁盘级别的文件
在这里插入图片描述

🥝 通过ps命令

ps aux 	 # 查看系统中所有的进程信息
ps axj	 # 可以查看进程的父进程号
  • ⚡ 查看对应进程信息
ps axj | head -1 && ps axj | grep myexe

在这里插入图片描述

四: 🔥 创建进程-fork() 📚

🍊 创建进程有两种创建方式:

    1. 使用 ./ 运行某一个可执行程序,这种是最常见的方式
    1. 使用系统调用接口创建进程,即使用fork()

当时用 fork() 函数之后,就在原来的进程中创建了一个子进程,在 fork() 之前的代码只被父进程执行,在 fork() 之后的代码有父子进程一起执行。

创建的子进程和父进程几乎一模一样,子进程和父进程的共享地址空间,子进程可以或者父进程中所有的文件,只有 PID 是父子进程最大的不同。

💢 下面是利用fork创建一个进程使用到的代码:

#include <iostream>    
#include <vector>    
#include <sys/types.h>    
#include <unistd.h>    
    
using namespace std;    
    
const int num = 10;    
    
void SubProcessRun()    
{    
    while(true)    
    {    
        cout << "T am sub process, pid: " << getpid() << " , ppid" << getppid() << endl;    
        sleep(1);    
    }    
}    
    
int main()    
{    
    vector<pid_t> allchild;    
    for(int i = 0; i < num; i++)    
    {    
        pid_t id = fork();    
        if(id == 0)    
        {    
            // 子进程    
            SubProcessRun();    
        }    
        allchild.push_back(id);    
    }    
    
    cout << "我的所有孩子是:";    
    for(auto child : allchild)    
    {    
        cout << child;    
    }    
    cout << endl;    
    
    while(true)    
    {    
        cout << "我是父进程,pid:" << getpid() << endl;    
        sleep(1);                                                                                                                                                                                                                                                                 
    }    
    return 0;    
} 

以下是运行结果:
在这里插入图片描述

如果fork成功创建了一个进程,那么上面的代码就会输出

T am sub process, pid: 27894 , ppid27891
我的所有孩子是:27892 27893 27894 27895 27896 27897 27898 27899 27900 27901 

这里面有很多有意思的点:

  • fork函数调用一次,返回两次。

🎯 上面的代码是如何实现执行两个不同的分支语句的呢?其实是因为fork函数会返回两个返回值,一个是子进程会返回0,一个是父进程会返回子进程的PID。所以会同时进程两个分支语句中。

  • 并发执行

🎯 父子进程是两个并发运行的独立程序。并发(同一个cpu执行),就是两个执行流在执行的时间上有重叠的部分。也就是说父子进程谁先被调度是不能确定的。

  • 相同但是独立的地址空间

🎯 两个进程其实地址空间是一样的,但是它们都有自己私有的地址空间,所以父子进程的运行都是独立的,一个进程中的内存不会影响另一个进程中的内存。

  • 共享文件

🎯 子进程继承了父进程所有打开的文件,所以父进程调用fork的时候,stdout文件呢是打开的,所以子进程中执行的内容也可以输出到屏幕上。

五: 🔥 进程状态

🥝 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。

  • 💦 下面的状态在 kernel 源代码里定义
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
  • R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

🎯 模拟实现:

  • 可以运行任意一个可运行的程序,即可出现R状态。
  • S睡眠状态(sleeping) : 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。

这种状态是一种浅度睡眠,此时的进程是在被阻塞的状态中,等待着条件的满足过后进程才可以运行。在这种状态下可以被信号激活,也可以被信号杀死。
模拟实现:
可以使用sleep() 系统调用接口使得一个进程睡眠

#include <stdio.h>
int main()
{
   while (1) 
   {
    	printf("S睡眠状态\n");
       sleep(100); // 睡眠100秒
   }
   return 0;
}
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

🎯 模拟实现:
这种情况没法模拟,一般都是一个进程正在对IO这样的外设写入或者读取的时候,为了防止操作系统不小心杀掉这个进程,所以特地创建出一个状态保护这种进程。

  • T停止状态(stopped)可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

🎯 模拟实现:
可以使用信号

kill -SIGSTOP PID 		// 停止进程
kill -SIGSONT PID 		// 继续进程
  • X死亡状态(dead)这个状态只是一个返回状态,你不会在任务列表里看到这个状态。进程停止执行,进程不能投入运行。通常这种状态发生在接受到SIGSTOP、SIGTSTP、SIGTTIN、SIGOUT等信号的时候。

🎯 模拟实现:
可以使用 kill -9 PID即可杀死一个进程

  • Z僵死状态
    后面会详细讲解

  • 孤儿进程如果父进程比子进程先退出,那么此时子进程就叫做孤儿进程。而操作系统不会让这个子进程孤苦伶仃的运行在操作系统中,所以此时孤儿进程会被 init 进程(也就是1号进程,即所有进程的祖先)领养,从此以后孤儿进程的状态和最后的PCB空间释放都是由init进程负责了。

🎯 模拟实现:
模拟实现让父进程比子进程提前退出即可

#include <stdio.h>      
#include <unistd.h>    
#include <sys/type.h>
    
int main()    
{    
    pid_t pid = fork();    
    
    if (pid == 0) {    // 子进程一直执行
        while (1) {    
            printf("I am a child, pid=%d, ppid=%d\n", getpid(), getppid());    
            sleep(1);    
        }    
    } else {    
        int count = 3;    // 父进程执行3次
        while (count --) {    
            printf("I am a father, pid=%d, ppid=%d\n", getpid(), getppid());    
            sleep(1);
        }    
    }    

    return 0;    
}

🥝 进程状态查看

ps aux / ps axj 命令
# 每隔一秒显示进程的信息
while :; do ps axj | head -1 && ps axj | grep code | grep -v grep; sleep 1; done

在这里插入图片描述

父进程退出后,自己子进程被1号init进程收养。

  • 僵尸进程
  1. 为什么会出现僵尸进程?

💦 前面说过进程的作用是为了给操作系统提供信息的,所以在进程调用结束之后,应该将该进程完成的任务情况汇报(eixt code)给操作系统,但是进程在执行完之后已经结束了,所以此时进程的状态就是僵尸状态。

  1. 僵尸进程的概念

💦僵尸进程:即进程已经结束了,但是父进程没有使用wait()系统调用,此时父进程不能读取到子进程退出返回的信息,此时就该进程就进入僵死状态。

  1. 僵尸进程的危害

💦 进程已经结束了,但是进程控制块PCB却还是没有被释放,这时就会浪费这一块资源空间。所以会导致操作系统的内存泄漏。

  1. 如何消灭僵尸进程?

💦 僵死状态需要父进程发出wait()系统调用终止进程,如果父进程不终止进程,那么此时要消灭僵尸进程只能通过找到僵尸进程的父进程,然后kill掉这个父进程,然后僵尸进程就会成为孤儿进程,此时由init进程领养这个进程然后杀死这个僵尸进程。

  • 🎯 模拟实现:
    模拟实现让子进程比父进程提前退出。
#include <stdio.h>      
#include <unistd.h>    
#include <sys/type.h>
    
int main()    
{    
    pid_t pid = fork();    
    
    if (pid == 0) {    
        int count = 3;    // 子进程执行3次
        while (count --) {    
            printf("I am a child, pid=%d, ppid=%d\n", getpid(), getppid());    
            sleep(1);    
        }    
    } else {    // 父进程一直执行
        while (1) {    
            printf("I am a father, pid=%d, ppid=%d\n", getpid(), getppid());    
            sleep(1);
        }    
    }    

    return 0;    
}

💦 使用shell脚本监控

# 每隔一秒显示进程的信息
while :; do ps axj | head -1 && ps axj | grep code | grep -v grep; sleep 1; done

在这里插入图片描述

  • 如上图:子进程执行了3次之后,编程僵尸状态

🍊 进程状态转化

在这里插入图片描述

六: 🔥 共勉

以上就是我对 【Linux】进程管理 的理解,会立刻更新下一篇的,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉
在这里插入图片描述

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

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

相关文章

小程序视频编辑SDK解决方案,轻量化视频制作解决方案

面对小程序、网页、HTML5等多样化平台&#xff0c;如何轻松实现视频编辑的轻量化与高效化&#xff0c;成为了众多开发者和内容创作者共同面临的挑战。正是洞察到这一市场需求&#xff0c;美摄科技推出了其领先的小程序视频编辑SDK解决方案&#xff0c;为创意插上翅膀&#xff0…

线性代数(持续更新)

一.矩阵及其计算 1.矩阵的概念 矩阵就是一个数表 元素全是0&#xff0c;是零矩阵&#xff0c;用0来表示 当mn时&#xff0c;称为n阶矩阵&#xff08;方阵&#xff09; 只有一行的叫行矩阵&#xff0c;只有一列的叫列矩阵 只有对角线有元素的叫做对角矩阵&#xff0c;用dia…

FTP被动模式配置

FTP被动模式配置 非云服务器或未开启防火墙的服务器不需要设置 背景&#xff1a; 某些FTP客户端与FTP服务器进行数据交互时&#xff0c;客户端数据传输使用的是被动模式&#xff1b; 被动模式会导致服务端的数据通道端口随机变动&#xff0c;服务器的防火墙无法设置放行规则…

Excel数据检视——对角线连续数据连线

实例需求&#xff1a;数据表如下图所示&#xff0c;现需要根据规则&#xff0c;在符合要求的单元格上&#xff0c;添加连线。 连续单元格位于对角线方向单元格内容相同连续单元格数量不少于7个 示例代码如下。 Sub LT2RB()Dim objDic As Object, rngData As Range, bFlag As …

基于springBoot校园健康驿站管理平台(源码+教程)

互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差&#xff0c;劳…

开源标注工具

DoTAT https://github.com/FXLP/MarkTool 后端代码未开放&#xff0c;可能有数据泄露风险 Chinese-Annotator https://github.com/deepwel/Chinese-Annotator 安装非常麻烦&#xff0c;github更新频率比较低&#xff0c;支持功能和doccano类似 IEPY https://github.com/ma…

头戴式蓝牙无线耳机哪个牌子比较好?头戴式蓝牙耳机排行榜盘点

在当今快节奏的生活中&#xff0c;音乐已成为我们不可或缺的精神食粮&#xff0c;而一款优秀的头戴式蓝牙无线耳机&#xff0c;不仅能为我们带来高品质的音频享受&#xff0c;还能让我们在繁忙的生活中找到片刻的宁静与放松&#xff0c;那么头戴式蓝牙无线耳机哪个牌子比较好&a…

【工具变量】数字技术应用广度与深度数据集(2001-2023年)

数据简介&#xff1a;数字技术应用广度是指企业为了实现收集、存储与处理海量数据时所需要的技术支撑&#xff0c;诸如大数据、云计算、区块链等等。数字技术应用深度包括数字化管理和数字化生产。其中&#xff0c;数字化管理是指企业应用数字技术实现组织、生产、销售和服务智…

Unreal Engine 5 C++: Asset Batch Duplication插件编写02

目录 准备工作 "Scripting library" 三个最重要的功能&#xff08;前两个是UEditorUtilityLibrary中的&#xff09; 自动创建声明&#xff1a; TArray T 的含义 F 的含义 Live Coding &#xff08;Ctrlalt F11&#xff09; Live Coding 的工作流程&#xff…

uni-app - - - - - 实现锚点定位和滚动监听功能(滚动监听功能暂未添加,待后续更新)

实现锚点定位和滚动监听功能 1. 思路解析2. 代码示例 效果截图示例&#xff1a; 点击左侧menu&#xff0c;右侧列表数据实现锚点定位 1. 思路解析 点击左侧按钮&#xff0c;更新右侧scroll-view对应的scroll-into-view的值&#xff0c;即可实现右侧锚点定位滚动右侧区域&am…

攻防世界--->robots

学习笔记。 robots&#xff1a; 得&#xff0c;就是隐藏某些东西呗。 - - 好吧&#xff0c;还是不会。 参考&#xff1a; 攻防世界——新手区——robots_robots flag-CSDN博客https://blog.csdn.net/weixin_45864041/article/details/108036234 突破点&#xff1a; so&#…

u-navber自定义导航栏搜索框

效果 代码 <template><view><u-navbar :is-back"false"><view class"navbar"><view class"search"><image src"../../static/my_device/search_icon.png" class"search_image"></i…

代码随想录算法day40 | 动态规划算法part13 | 647. 回文子串,516.最长回文子序列

647. 回文子串 动态规划解决的经典题目&#xff0c;如果没接触过的话&#xff0c;别硬想 直接看题解。 力扣题目链接(opens new window) 给定一个字符串&#xff0c;你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的…

箱包发霉怎么清洁霉斑 工厂箱包发霉翻箱处理方法

箱包是我们日常生活中的必备品&#xff0c;随着箱包工厂订单不断&#xff0c;但工厂最头疼的就是会经常遇到批量的箱包出现发霉的问题。一旦发霉&#xff0c;并要面临一笔巨额索赔问题&#xff0c;尤其出口到国外发霉了&#xff0c;经ihaoer防霉人士介绍一种简单有效的方法&…

apple developer 开发者账号被停用,提示Locked,终于解决了

事情是这样的&#xff0c;9.11我们要发布app的时候&#xff0c;一直登录不上。然后联系了苹果客服&#xff0c;告知账号不活跃。于是让我们通过活跃申请、以及重置密码申请操作来解决。 然后&#xff0c;操作一遍又一遍&#xff0c;都解决不了。 后来联系可国外的客服&#…

新能源行业的福音,复合机器人助力打造智能无人化充电站

随着工业自动化和智能化水平的不断提升&#xff0c;无人化作业已成为现代生产线的必然趋势。在山西地区的室内生产条件下&#xff0c;富唯智能凭借其在自卸车充电系统领域的深厚积累&#xff0c;成功设计出一套高效、稳定的自卸车自动充电系统&#xff0c;为工业领域带来革命性…

ssm协同办公系统-计算机毕业设计源码42133

摘要 随着信息技术的迅猛发展&#xff0c;协同办公系统在企业和组织中扮演着越来越重要的角色。本研究旨在基于SSM框架、Java编程语言和MySQL数据库&#xff0c;设计和开发一个协同办公系统。首先&#xff0c;介绍了协同办公系统的背景和意义&#xff0c;详细阐述了系统的功能模…

Git - 版本管理

本文我们来介绍下 Git 管理版本的几个常用命令。 ‍ git log&#xff1a;查看提交日志 随着对文件的不断修改与提交&#xff0c;Git 帮我们管理了之前的各个版本。就好比玩一个能存档的游戏&#xff0c;每过一关就能帮我们存档&#xff0c;如果某一关没打过&#xff0c;就可…

告别繁琐!用 Light To Freedomen一键打造你的专属后台管理系统

作为开发者&#xff0c;特别是后端开发人员&#xff0c;前端开发工作往往是一项让人头疼的挑战。复杂的UI设计&#xff0c;数据展示和交互逻辑&#xff0c;不仅费时费力&#xff0c;还容易出现各种问题。然而&#xff0c;后台管理系统作为企业应用的核心模块&#xff0c;又是无…

uboot以tag结构体的方式给内核传参,cmdline,bootargs,以及uboot如何启动内核

uboot以tag结构体的方式给内核传参&#xff0c;cmdline&#xff0c;bootargs&#xff0c;以及uboot如何启动内核 一、u-boot启动流程 1、第一阶段 cpu/s3c24xx/start.S 主要是一些依赖于 CPU 体系结构的代码,比如硬件设备初始化代码 等。这一阶段的代码主要是通过汇编来实现…