进程概念、PCB及进程查看

news2025/4/5 2:56:59

文章目录

  • 一.进程的概念
    • 进程控制块(PCB)
  • 二.进程查看
    • 通过指令查看进程
    • 通过proc目录查看
    • 进程的`cwd`和`exe`
    • 获取进程pid和ppid
    • 通过fork()创建子进程

一.进程的概念

进程是一个运行起来的程序,而程序是存放在磁盘的,cpu要想执行程序的指令,需要先将程序加载到内存中。

课本概念:进程是被加载到内存运行的程序
内核观点:担当分配系统资源(CPU时间,内存)的实体。

操作系统中有着大量的进程,操作系统作为管理者,管理的其实是大量进程相关的数据,那么如何管理这些数据呢?

先描述,再组织

当二进制代码直接加载到内存时,操作系统为了更好地管理加载的程序,创建了描述该进程的数据结构。这样,操作系统只用看这个数据结构,不用管各种复杂多样的二进制代码,并且将它们组织起来进行管理

进程控制块(PCB)

这个数据结构叫PCB(process control block),进程信息被放在其中,可以理解为进程属性的集合,在linux的PCB是task_struct

struct task_struct {
 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
 struct thread_info *thread_info;
 atomic_t usage;
 unsigned long flags; /* per process flags, defined below */
 unsigned long ptrace;

 int lock_depth;  /* Lock depth */

 int prio, static_prio;
 struct list_head run_list;
 prio_array_t *array;
 //.....
}

当有一个程序被加载到内存时,操作系统会为该进程在内存中创建一个task_struct类型的对象,并将该进程放入双链表等其他结构中。这样,操作系统对进程的管理就变为操作系统对PCB的管理,再变为操作系统对双链表等结构的增删查改等操作

由此可以总结:进程 = 内核数据结构(PCB等)+ 可执行程序(代码+数据)

二.进程查看

通过指令查看进程

为了让进程能够一直运行方便观察,写一个死循环程序,让其每隔1秒钟打印一句话。

#include <stdio.h>
#include <unistd.h>
 
int main()
{
    while(1){
        printf("It's a process.\n");
        sleep(1);
    }
    return 0;
}

随后运行它,此时该程序变成了一个进程:
在这里插入图片描述

接着就可以用ps指令查看进程信息,同时配合grep进行抓取

ps ajx | grep myprocess

得到以下结果:
在这里插入图片描述

可以看到系统中关于myprocess的进程一共有两个,第一行是我们写的运行的程序,第二行是grep命令进行抓取的进程。展示了各种信息:PPID、PID、PGID等等,这些就是PCB的一部分。
注意:task_struct是内核数据结构,查看进程信息读取该数据,必须要通过系统调用。

通过proc目录查看

proc是一个目录,里面存放当前系统实时的 进程信息
ls /proc
在这里插入图片描述

这里的数字就是进程的PID,由于此时已经将myprocess进程停止,此目录并没有找到名为167647的目录。
但是,仔细看,却有165058,这是刚才myprocess的父进程ID即PPID,通过指令可以知道,该进程其实就是bash
在这里插入图片描述

再次运行myprocess,并且通过指令得到其PID,进入该文件夹,可以发现进程的数据显式存在文件中。

在这里插入图片描述

进程的cwdexe

查看该目录详细信息,有两个文件很瞩目
在这里插入图片描述

cwd: Current Work Directory 指出该进程当前工作路径
exe: 指出该进程可执行程序的磁盘文件

修改程序,添加一个fopen函数

#include <stdio.h>
#include <unistd.h>
 
int main() 
{
    FILE* fp = fopen("1.txt", "w");  // 若不存在就创建
    while (1) 
        {
        printf("It's a process.\n");
        sleep(1);
    }
}

在这里插入图片描述

这恰好就是cwd链接的目录,说明fopen使用了查看cwd的系统调用。


再看exe,此时进程运行中,直接删除其链接在磁盘中的文件,发现进程没有终止,停止进程再运行显然就会失败了。
在这里插入图片描述

运行程序,本质就是将其从磁盘拷贝至内存中,进程与其磁盘上对应程序没有直接关系。

获取进程pid和ppid

可以直接通过系统调用getpid()getppid()得到当前进程的pid和ppid(父进程的pid),返回值为pid_t类型,底层就是整数。

运行以下代码

#include <stdio.h>
#include <unistd.h>

int main()
{
    while (1)
    {
        printf("It's a process.\t");
        printf("pid:%d, ppid:%d\n",getpid(), getppid());
        sleep(1);
    }
    return 0;
}

可以看到打印出当前进程的pidppid
在这里插入图片描述

通过ps axj | head -1; ps axj | grep 184670进行验证,当前进程是./myprocess且其父进程是bash

在这里插入图片描述

通过fork()创建子进程

通过man指令查看fork()函数细节
在这里插入图片描述

fork()函数可以创建子进程,创建成功后父子进程代码共享。
若成功创建,子进程的pid返回给父进程,0返回给子进程;
若失败,-1返回给父进程,没有子进程。

代码共享可以通过以下代码得到验证

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 
int main() 
{
    printf("before\n");
    fork();
    printf("Hello, pid:%d\n", getpid());
}

fork()之前的代码只执行了一次,之后的代码执行了两次,这两次分别是两个进程执行的。
在这里插入图片描述


创建父子进程是为了做不同的事情,一般是通过if/else来进行分流达到的,这恰恰用到了fork()有两个返回值的特点,下面的代码若是初见一定会迷惑。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 
int main() 
{
   pid_t id = fork();

   // id: 0-子进程 >0-父进程
   if (id == 0)
   {
        while(1)
        {
            printf("child process, pid: %d, ppid: %d", getpid(), getppid());
            sleep(1);
        }
   }
   else
   {
    while(1)
        {
            printf("father process, pid: %d, ppid: %d", getpid(), getppid());
            sleep(1);
        }
   }
}

利用父子进程fork()返回值不同,达到两个死循环都在不断执行的效果:
在这里插入图片描述

通过指令查看,确实两个进程是父子进程关系:

在这里插入图片描述


下面来简要分析上面的情况,具体细节会在之后进程地址空间部分详谈。

  1. 为什么两个死循环会同时执行❓

上节讲过,进程 = 内核数据结构(PCB等)+ 可执行程序(代码+数据)。通过fork()创建子进程,肯定也要给子进程创建一个独立的task_struct,而其代码和数据指向了父进程接下来的代码和数据。子进程的大部分属性值也是由父进程拷贝而来,修改前地址不会改变。
在CPU角度,它不会管谁是父进程,谁是子进程,会在操作系统的管理下并发执行。在我们的视角下,两个死循环同时执行了。

  1. 为什么fork()返回值如此设计❓

父与子的关系是一对一或者一对多的。这样的关系导致父找子并不容易,所以创建子进程成功后需要把子进程的pid返回给父进程,方便父进程控制子进程。
而子找父是很容易的,通过系统调用getppid()即可。

  1. 为什么fork()会返回两次值❓

fork()之前只有父进程,即只有父进程才能调用fork()fork()内部在return之前肯定已经将子进程创建成功,又子进程和父进程在创建成功后代码共享,那么子进程和父进程都会执行return这条语句,这也就是为什么fork()会返回两次值。

  1. 同一个变量id怎么会既大于0,又等于0❓

进程之间具有独立性,一个进程崩溃了,不会影响另一个进程。这里的id是父子进程的共享数据,若父子进程对共享数据有写操作,这时操作系统会将该数据拷贝两份,这就是写时拷贝。那么此时,虽然这是同一个变量名,但实际上表示的是不同的值,那么id出现两种情况也就不足为奇了,实际在底层的空间根本就不是一个。

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

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

相关文章

php session数据存储位置选择

PHP session 数据的存储位置可以通过配置文件或者代码来进行设置。默认情况下&#xff0c;session 数据是存储在服务器的文件系统中的。你可以将 session 数据存储在其他地方&#xff0c;例如数据库、缓存等。 基础概念 PHP session默认情况下将数据存储在服务器端的临时文件中…

计算机网络————(一)HTTP讲解

基础内容分类 从TCP/IP协议栈为依托&#xff0c;由上至下、从应用层到基础设施介绍协议。 1.应用层&#xff1a; HTTP/1.1 Websocket HTTP/2.0 2.应用层的安全基础设施 LTS/SSL 3.传输层 TCP 4.网络层及数据链路层 IP层和以太网 HTTP协议 网络页面形成基本 流程&#xff1a…

【Viewer.js】vue3封装图片查看器

效果图 需求 点击图片放大可关闭放大的 图片 下载 cnpm in viewerjs状态管理方法 stores/imgSeeStore.js import { defineStore } from pinia export const imgSeeStore defineStore(imgSeeStore, {state: () > ({showImgSee: false,ImgUrl: ,}),getters: {},actions: {…

数据结构之二叉树的定义及实现

1. 树的概念 主要的定义&#xff1a; 节点的度&#xff1a;一个节点含有的子树的个数称为该节点的度&#xff1b;如上图&#xff1a;A的为6 叶节点或终端节点&#xff1a;度为0的节点称为叶节点&#xff1b;如上图&#xff1a;B&#xff0c;C&#xff0c;H&#xff0c;I等节点…

Rust语言基础知识详解【一】

1.在windows上安装Rust Windows 上安装 Rust 需要有 C 环境&#xff0c;以下为安装的两种方式&#xff1a; 1. x86_64-pc-windows-msvc&#xff08;官方推荐&#xff09; 先安装 Microsoft C Build Tools&#xff0c;勾选安装 C 环境即可。安装时可自行修改缓存路径与安装路…

SQLMesh 系列教程9- 宏变量及内置宏变量

SQLMesh 的宏变量是一个强大的工具&#xff0c;能够显著提高 SQL 模型的动态化能力和可维护性。通过合理使用宏变量&#xff0c;可以实现动态时间范围、多环境配置、参数化查询等功能&#xff0c;从而简化数据模型的开发和维护流程。随着数据团队的规模扩大和业务复杂度的增加&…

【Deepseek】Linux 本地部署 Deepseek

前言 本文介绍在 Linux 系统上部署 Deepseek AI。本文教程是面向所有想体验 AI 玩家的一个简易教程&#xff0c;因此即使是小白也可以轻松完成体验&#xff0c;话不多说立马着手去干。 [注]&#xff1a;笔者使用的系统为 Ubuntu 24.10 1. 关于 ollama Ollama 是一款开源应用…

git,bash - 从一个远端git库只下载一个文件的方法

文章目录 git,bash - 从一个远端git库只下载一个文件的方法概述笔记写一个bash脚本来自动下载get_github_raw_file_from_url.shreanme_file.shfind_key_value.sh执行命令 END git,bash - 从一个远端git库只下载一个文件的方法 概述 github上有很多大佬上传了电子书库&#xf…

臻识相机,华夏相机,芊熠车牌识别相机加密解密

臻识&#xff0c;华夏&#xff0c;芊熠这三种车牌识别相机解密我都试过了&#xff0c;可以正常解密成功&#xff0c;其它品牌我暂时没有测试。超级简单&#xff0c;免费的&#xff0c;白嫖无敌&#xff01; 流程&#xff1a; ①&#xff1a;先导出配置文件&#xff0c;例如我以…

网络安全与措施

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 # 网络安全问题概述 1) 数据安全 访问&#xff08;授权访问&#xff09;&#xff1b;存储&#xff08;容灾、备份或异地备份等&#xff09; 2) 应用程序 不能…

前后端分离系统架构:基于Spring Boot的最佳实践

前后端分离系统架构图描绘了一个基于Springboot的前端后台分离的系统架构。它强调了前端&#xff08;客户端&#xff09;与远程&#xff08;服务器&#xff09;的解耦&#xff0c;通过API接口进行交互&#xff0c;分别独立开发和部署。 前后端分离系统架构图 从上到下&#xff…

内外网文件传输 安全、可控、便捷的跨网数据传输方案

一、背景与痛点 在内外网隔离的企业网络环境中&#xff0c;员工与外部协作伙伴&#xff08;如钉钉用户&#xff09;的文件传输面临以下挑战&#xff1a; 安全性风险&#xff1a;内外网直连可能导致病毒传播、数据泄露。 操作繁琐&#xff1a;传统方式需频繁切换网络环境&…

抖音试水AI分身;腾讯 AI 战略调整架构;百度旗下小度官宣接入DeepSeek...|网易数智日报

抖音试水AI分身&#xff0c;字节旗下AI智能体平台扣子已与抖音打通&#xff0c;相关功能内测中 2月19日消息&#xff0c;钛媒体App独家获悉&#xff0c;字节旗下AI智能体开发平台扣子&#xff08;Coze&#xff09;已与抖音打通&#xff0c;抖音创作者可在扣子智能体平台打造AI分…

红帽7基于kickstart搭建PXE环境

Kickstart 文件是一种配置文件&#xff0c;用于定义 Linux 系统安装过程中的各种参数&#xff0c;如分区、网络配置、软件包选择等。system-config-kickstart 提供了一个图形界面&#xff0c;方便用户快速生成这些配置文件。 用户可以通过图形界面进行系统安装的详细配置&…

安装PHPStudy 并搭建DVWA靶场

目录 一、PHPStudy 简介 二、DVWA 简介 三、安装 PHPStudy 四&#xff1a;安装 DVWA 一、PHPStudy 简介 phpstudy傻瓜式的一键启动&#xff0c;支持WAMP、WNMP、LAMP、LNMP&#xff0c;一键切换环境&#xff08;nginxapahce&#xff09;,一键切换PHP版本&#xff08;5.1-7…

SQL写法技巧

目录 1.批量插入&#xff0c;查询&#xff0c;删除数据 缺点 实现方法 1.批量插入数据 2.批量查询数据 3.批量删除数据 4.批量修改数据 解释 2.树型表查询 方法一&#xff1a;递归(适用于多级的情况) 方法二&#xff1a;表的自连接 方法三&#xff1a;MySQL递归&am…

Ryu:轻量开源,开启 SDN 新程

1. Ryu 控制器概述 定位&#xff1a;轻量级、开源的SDN控制器&#xff0c;专为开发者和研究人员设计&#xff0c;基于Python实现。开发者&#xff1a;由日本NTT实验室主导开发&#xff0c;遵循Apache 2.0开源协议。核心理念&#xff1a;简化SDN应用开发&#xff0c;提供友好的…

【核心算法篇十四】《深度解密DeepSeek量子机器学习:VQE算法加速的黑科技与工程实践》

在经典计算机逼近物理极限的今天,量子计算正以指数级加速潜力颠覆传统计算范式。想象一下,一个需要超级计算机运算千年的化学分子模拟问题,用量子计算机可能只需几分钟——这就是DeepSeek团队在VQE(Variational Quantum Eigensolver)算法加速实践中创造的奇迹。根据,VQE作…

“国补”带火手机换新,出售旧手机应如何保护个人信息安全

在“国补”政策的推动下,手机换新热潮正席卷而来。“国补”以其诱人的补贴力度,成功激发了消费者更换手机的热情。无论是渴望体验最新技术的科技爱好者,还是对旧手机性能不满的普通用户,都纷纷投身到这场手机换新的浪潮之中。 随着大量消费者参与手机换新,二手手机市场迎来…

数据结构:基数排序(c++实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 基数排序的定义和基本原理基本原理具体步骤 基数排序的优缺点&#xff1a;代码实现总结 基数排序的定义和基本原理 基数排序(Radix Sort)是一…