【Linux】Linux进程基础

news/2024/10/19 15:25:52/

1.进程介绍与概念

进程的本质是在计算机内存中运⾏的程序,但是这⼀个概念太过于⼴泛

每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运行,所有的硬件资源都被这个程序在使用。这种假象是通过抽象了一个进程的概念来完成的,进程可以说是计算机科学中最重要和最成功的概念之一。

进程是操作系统对一个正在运行的程序的一种抽象,换言之,可以把进程看做程序的一次运行过程;同时,在操作系统内部,进程又是操作系统进行资源分配的基本单位。

要了解进程,⾸先采⽤前⾯在操作系统基础中介绍的思想「先描述,再组织」,每⼀ 个进程本质也是⼀个结构(⼀般称为PCB(Process Control Block,进程控制 块),在Linux下的PCB称为 task_struct ),计算机将程序加载到内存,就会在 内存中添加⼀个进程,那么此时就会形成⼀个结构体,该结构体中存在进程的⼀些描 述,例如进程的在内存中的位置、进程的编号、对应数据和代码的地址等,在程序执 ⾏前,进程会被排列到⼀个数据结构,通过操作系统调度器从数据结构中取出进程就 代表对应的进程获取到CPU的使⽤权,此时就会通过对应进程的结构体中的相关数据 加载代码和数据进⾏运算、逻辑处理,从⽽到达执⾏程序的效果

这⼀过程可以看出,进程=程序代码和数据+进程结构体 进程可以粗略得分为两种:

1. 执⾏完对应代码就退出

2. ⼀直运⾏在后台,也被称为「常驻进程」

2.Linux下查看进程

⾸先,通过下⾯的C语⾔代码创建⼀个进程:

#include <stdio.h>
#include <unistd.h>int main() 
{    while(1) {printf("hello world\n");sleep(1);}return 0;
}

对应的Makefile代码如下:

TARGET=process 
SRC=process.c$(TARGET):$(SRC)gcc -o $@ $^.PHONY:clean
clean:rm -rf $(TARGET)

编译运⾏前⾯的C语⾔代码,并在Linux下查看对应进程

可以使⽤下⾯的⽅式:

ps ajx | head -1 && ps ajx | grep process# 如果存在部分干扰信息,可以使用结合管道和grep的-v指令对部分干扰信息的关键字进行过滤

上⾯的指令中的 ps ajx代表查看当前系统运⾏时所有的进程以及部分信息,直接执 ⾏就可以看到进程信息

可以看到对应的进程为:

在Linux下实际上进程都被保存在⼀个名为 proc 的⽬录下,这个⽬录不是存在于磁 盘中的⽬录,⽽是操作系统运⾏时进程出现创建的,使⽤下⾯的命令查看该⽬录:

ls /proc

proc ⽬录在根⽬录下,与 home ⽬录同级

再次运⾏前⾯的C语⾔代码,使⽤下⾯的代码查看程序进程信息以及在 proc下的位置

3.结束进程的方式

在Linux下,可以使⽤两种⽅式结束进程:

1. 快捷键 ctrl+c

2. 使⽤ kill 指令: Kill -9 进程PID

4.进程对应程序文件位置

在前⾯C语⾔程序对应的进程⽬录中除了可以看到 cwd 以外,还可以看到⼀个名为 exe 的软链接,该链接指向着⼀个路径,如下:

该路径对应的即为加载到内存中的代码和数据(进程组成的⼀部分),如果在运⾏时 将该路径下的 process ⽂件删除,此时已经运⾏的进程不会受到影响,因为对应的 代码和数据已经加载进内存,受影响的只是下⼀次⽆法直接使⽤运⾏程序的⽅式创建 进程

删除后再次查看结果如下:

5.进程PID与 PPID

PID 是Linux系统下每⼀个进程对应的⼀个编号,该编号会因为进程产⽣的时间不同 ⽽不同,例如每⼀次运⾏前⾯的C语⾔代码都会得到⼀个不同的PID

如果想获取到当前进程的 PID 可以使⽤getpid()函数 该函数原型如下:

 pid_t getpid(void);

其中p id_t 类似于 long 类型,是⼀个⻓整型,该函数不需要传递形参

在前⾯的C语⾔代码中添加该函数并打印该进程的 PID 对⽐使⽤指令查看进程信息下的PID

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() 
{   pid_t id = getpid();while(1) {printf("hello world, pid = %d\n", id);sleep(1);}return 0;
}

可以看到PID⼀致

⼀般连续创建的进程,PID 是连续的     PID 是进程的编号    PPID 是指定进程的⽗进程的编号,当前进程也被称为对应⽗进程的⼦进程

同样,在代码中想获取到当前进程的⽗进程对应的 PPID ,可以使⽤ getppid() 函 数,原型如下:

pid_t getppid(void);

对前⾯C语⾔的代码进⾏修改,如下:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() 
{   pid_t id = getpid();pid_t pid = getppid();while(1) {printf("hello world, pid = %d ppid = %d\n", id, pid);sleep(1);}return 0;
}

多次运⾏代码后结果如下:

可以发现,每⼀次运⾏代码, PID 都会改变,但是 PPID 始终不变,因为其⽗进程始 终是同⼀个进程,通过查看进程的指令可以找到 PID 为14901对应的⽗进程:

bash 是Linux下的指令解释器,每⼀次执⾏指令时,实际上就是将对应的指令交给 了bash,由 bash 再交给操作系统进⾏执⾏,当执⾏上⾯程序的进程时,实际上是 创建了⼀个 bash 的⼦进程,再由⼦进程执⾏对应的程序代码和数据

6.创建子进程 fork

6.1简单了解 fork函数

fork 函数原型如下:

pid_t fork(void);

在Linux编程⼿册中对 fork 的解释如下:

对应的函数返回值的解释如下:

⼤意为:成功的情况下,该函数返回⼦进程的 PID 给⽗进程,返回0给⼦进程。失败 的情况下,该函数返回-1给⽗进程,不创建任何⼦进程,并恰当设置错误代码

6.2简单使用 fork函数

根据前⾯对 fork 函数的介绍,修改前⾯的C语⾔代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main() 
{   pid_t id = fork();if(id > 0) {printf("I am prarent process, my pid = %d my ppid = %d\n", getpid(), getppid());} else if(id == 0) { printf("I am child process, my pid = %d my ppid = %d\n", getpid(), getppid());}return 0;
}

运行结果如下:

可以看到,⼦进程的 PPID 即为⽗进程 PID ,与前⾯的思想对应

7.简单了解 fork细节

上⾯的代码中⼀共存在着三个待解决的问题:

1. 使⽤ fork 创建⼦进程,为什么可以通过if 和 else if区分⼦进程和⽗进程

对于第⼀个问题来说,根据 fork 函数的返回值描述,当函数运⾏成功的情况下,会 返回⼦进程的 PID 给⽗进程, PID ⼀般都是⼤于0的,⽽⼦进程会收到 返回值为0,所以当上⾯代码中的id变量⼤于0时,就会⾛ fork 函数的 if 语句,⽽唯⼀⼀个接 收到的id⼤于0的就是⽗进程;同理,⼦进程的id变量等于0,就会⾛ else if 语句。

2. 为什么 fork 函数出现了两个返回值

对于第⼆个问题来说,实际上执⾏ fork 函数时,在返回 pid 之前就已经执⾏完了创 建⼦进程逻辑,此时⽗进程和⼦进程共享代码,但是各⾃独⽴数据,⽗进程拥有⾃⼰ 的返回值,⼦进程也拥有⾃⼰的返回值,所以此时 return 的时候是每个进程返回各 ⾃的返回值

3. 为什么两个分⽀语句if和 else if都执行了

对于第三个问题来说,当代码执⾏到 fork 函数时,会执⾏ fork 函数的内部逻辑, 再执⾏完其主逻辑代码后,就已经创建出了⼦进程(对应存在⼀个⼦进程的 task_struct ),此时⼦进程会与⽗进程共享同⼀块代码,但是⼦进程拥有⾃⼰的 数据,并使⽤⾃⼰的数据执⾏代码。⽽之所以需要共享同⼀块代码,是因为⽗进程的 代码是从硬盘中加载的,但是⼦进程的代码并不存在与硬盘,从⽽也就⽆法加载,⽽ 之所以不同的进程有着不同的数据,这是进程独⽴性的主要体现,可以⽤下图先简单 理解这个过程,具体过程会在进程地址空间讲解:

此处,⼦进程的 task_struct 实际上先是对⽗进程的task_struct 的拷⻉,再对其中的内容进⾏⼀定的修改;


http://www.ppmy.cn/news/1538789.html

相关文章

AI学习指南深度学习篇-迁移学习(Transfer Learning)简介

AI学习指南深度学习篇-迁移学习&#xff08;Transfer Learning&#xff09;简介 引言 在快速发展的人工智能 (AI) 和深度学习领域&#xff0c;数据和计算资源的需求不断增加。虽然深度学习模型在图像识别、自然语言处理等领域取得了巨大成功&#xff0c;但构建这些模型需要大…

C++入门基础知识112—【关于C++嵌套 switch 语句】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C嵌套 switch 语句的相关内容&#xff…

无感升级有三种常见的可行性方案:蓝绿部署、灰度发布、和滚动更新

A. 蓝绿部署 1. 前端 打包与部署: 构建前端: 使用构建工具(如 Webpack、Gulp)对前端项目进行打包。运行命令,例如: npm run build确保生成的文件有版本号或哈希,以防止缓存问题。上传静态文件: 将打包后的文件上传到绿色环境的路径(如 /var/www/html/v2)。示例: s…

highcharts样式记录

图表设置 const rendChart (min, max) > {Highcharts.setOptions({global: { useUTC: false },});Highcharts.chart(hourly-chart, {chart: {spacingBottom: 0,marginLeft: 53,marginTop: 10,marginBottom: 0,marginRight: 13,style: {fontSize: 0.2rem,color: #363a44,li…

Java_ EE (网络编程)

网络编程基本概念: 计算机网络计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络管理软件及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计算机系统。从其…

C语言指针(test_1_29)

C语言指针&#xff08;test_1_29&#xff09; add.c #define _CRT_SECURE_NO_WARNINGS 1int a 200;int print() {printf("4: %d\n", a); }static int g_val 2024;全局变量是具有外部链接属性的 但是被static 修饰后&#xff0c;外部链接属性就变成了内部链接属性…

facebook受众选择设置策略的最佳方式

在进行Facebookguanggao投放时&#xff0c;受众的选择是一个至关重要的步骤。正确的受众选择不仅能够帮助我们更好地定位目标用户&#xff0c;还能显著提高guanggao的转化率和投资回报率&#xff08;ROI&#xff09;。然而&#xff0c;受众选择的数量和范围同样是需要认真考虑的…

java数据库操作-cnblog

创建lib目录&#xff0c;填入jar包 选择 libraries添加lib目录 package nb;import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException;public class JDBCtest {private static final String url "jdbc:mysql://localhost:3306/test?c…