当前位置: 首页 > article >正文

Linux入门学习:进程概念

文章目录

    • 1. 什么是进程?
      • 1.1 基本概念
      • 1.2 task_struct
    • 2. 组织进程
    • 3. 查看进程
      • 3.1 父进程与子进程
      • 3.2 fork创建子进程
      • 3.3 kill
      • 3.4 /proc

1. 什么是进程?

1.1 基本概念

在课本的概念中,进程程序的一个执行实例,正在执行的程序。其内核观点:担当分配系统资源(CPU时间,内存)的实体。但这些概念太笼统,并不能让我们更加清晰的知道进程是什么,实际上,进程是内核数据结构(pcb) + 程序的代码与数据。

pcb(process control block)进程控制块,进程信息被放在一个叫pcb的数据结构中,可以理解为进程属性的集合。在Linux入门学习:深刻理解计算机硬件与OS体系中,我们已经了解到操作系统对我们的硬件进行管理的基本思想----先描述,后组织,pcb就是操作系统用于描述进程的数据结构。

Linux操作系统下的PCB是: task_struct,也就是说Linux描述进程的结构体叫做task_struct,task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

1.2 task_struct

在Linux系统中,task_struct一般包含以下信息:

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

2. 组织进程

Linux描述完进程task_struct,在内存中,他是怎么将他们组织起来的?答案:是以链表的形式组织起来的!

进程与进程之间:
在这里插入图片描述
在内存中,程序文件一般在磁盘,我们要运行时,先在内存中拷贝一份exe文件,再进程管理的指针中,插入新的task_struct,这个新的task_struct会有成员管理内存中加载的exe,并加载这个exe对应的属性到进程之中。

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针

在这里插入图片描述

由此,我们可以知道一个事实:我们在Windows双击一个exe文件,把他运行起来,实质上,就是在系统中创建了一个新的进程!在Linux中的,像ls , pwd指令,本质上也是运行了一个exe,创建了一个进程,只不过运行完就直接退出了,而在Windows上的很多软件是常驻进程,一般运行了之后就不会再退出了,没有"运行完"的说法,除非用户直接×掉,直接终止运行。

3. 查看进程

3.1 父进程与子进程

pid – 进程id
ppid – 父进程id

先要明白一个概念:在Linux操作系统中,创建新进程的时候,都是由自己的父进程创建的!!在C语言中,我们可以通过函数getpid与getppid,来查看当前启动的C语言程序的pid与ppid

我们先来观察一个现象:在Linux中写下这样的一段代码

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

int main()
{
	while(1)
	{
		printf("我是一个进程, 我的pid: %d, ppid, %d\n", getpid(), getppid());
	}
        
        return 0;
}

反复运行后:
在这里插入图片描述

我们发现反复运行后,每次的pid都不一样,但是他们的ppid,每次都是一样的!!为什么?

#查看对应进程的相关信息指令
ps axj | head -1 && ps ajx | grep 进程id

在这里插入图片描述

结论:这些进程的父进程都叫bash!!bash:命令行解释器。在命令行中,我们运行我们自己的可执行程序或者命令行指令本质是bash进程创建的子进程,由子进程 执行我们的代码! !

我们在登录的时候操作系统会自动为我们启动一个bash程序,bash前面有一个-,代表着我们是通过命令行终端进行登录的

3.2 fork创建子进程

在C语言中有一个函数fork,可以借用系统调用,来创建子进程,头文件是<unistd.h>,借此,我们在Linux写一个程序,来先看看现象:

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

int main()
{

    printf("父进程运行: pid: %d, ppid:%d\n", getpid(), getppid());
	
    pid_t id = fork();
    if (id == 0)
    {
        // 子进程
        while (1)
        {
            printf("我是子进程,我的pid: %d, ppid: %d,ret = %d\n", getpid(), getppid(),id);
            sleep(1);
        }
    }
    else
    {
        // 父进程
        while (1)
        {
            printf("我是父进程,我的pid: %d, ppid: %d,ret = %d\n", getpid(), getppid(),id);
            sleep(1);
        }
    }


    return 0;
}

运行之后
在这里插入图片描述

我们可以观察到一个奇怪的现象:为什么if和else的条件同时被满足了?!!竟然同时进行了两个循环?!!毫无疑问的,肯定是程序启动了两个进程,这其中的细节会衍生出很多问题:

Q1:代码中fork返回值是什么?

在这里插入图片描述

 pid_t id = fork();

如果fork成功创建进程,对于父进程的返回值为子进程的pid,子进程的返回值的0。如果创建失败,父进程的返回值为-1。由返回值的不同,满足if或else的不同条件,启动对应的循环。

——》父进程往往只有一个,而子进程往往有多个,给父进程返回子进程的id,是为了方便管理子进程。Linux进程的整体是一个树型结构!!



❓Q2:一个函数(fork)为什么能返回两次?两次的数据还不相同?!

我们的程序在fork之后,毫无疑问,会启动两个程序,这两个程序的关系是父子关系,一般而言,这两个程序的代码是共享的!但是数据是自己保有一份的!!
在这里插入图片描述

——》进程与进程之间是相互独立的! 多个进程之间,运行的时候,即使他们是父子,也不会相互影响,即使其中一个挂了,另一个也能正常运行。对于代码而言,任何进程对代码的权限只是可读的,所以不同的进程使用同一份代码就能得到安全型的保证。但是数据一定是独立的,对于父子进程,fork各自返回了一次,他们得到了各自的数据,各自对自己的数据进行处理,从而启动了不同的循环。

数据是独立的还有一个验证:

	int cnt = 0;
    if (id == 0)
    {
        // 子进程
        while (1)
        {
            printf("我是子进程,我的pid: %d, ppid: %d,cnt = %d\n,", getpid(), getppid(),cnt);
            sleep(1);
            cnt++;
        }
    }
    else
    {
        // 父进程
        while (1)
        {
            printf("我是父进程,我的pid: %d, ppid: %d,cnt = %d\n", getpid(), getppid(),cnt);
            sleep(1);
        }
    }

在这里插入图片描述

——》观察现象,父进程与子进程的cnt值各不相同。

3.3 kill

对于没有结束的进程,可以用kill指令将其杀掉

 kill -9 进程标示符

在这里插入图片描述

3.4 /proc

/proc目录里面存储文件不在磁盘上,里面的文件都是内存级的,在关机时会消失,开机时又会出现,它是对动态运行的所有进程的一个可视化信息
在这里插入图片描述
蓝色表示的是目录文件,因为一个进程里面可能会存在很多信息,进去看看
在这里插入图片描述
1、其中exe说明当前的进程是可以找到自己要执行的代码的(可视化出来了)。

2、cwd表示的是当前进程的工作目录(current work dir),所以为什么你fopen出来的新文件会被默认放在当前目录,这其实是由该进程的cwd决定的!!

本文就到这里,感谢你看到这里❤️❤️! 我知道一些人看文章喜欢静静看,不评论🤔,但是他会点赞😍,这样的人,帅气低调有内涵😎,美丽大方很优雅😊,明人不说暗话,要你手上的一个点赞😘!

希望你能从我的文章学到一点点的东西❤️❤️


http://www.kler.cn/a/318317.html

相关文章:

  • 利用编程语言和脚本编写技术,实现自动化渗透测试和安全工具的开发
  • 缓存与数据库不一致的解决方案:深入理解与实践
  • 量化交易系统开发-实时行情自动化交易-3.4.1.2.A股交易数据
  • acwing算法基础02一高精度,前缀和,差分
  • IEC60870-5-104 协议源码架构详细分析
  • wafw00f源码详细解析
  • k8s前置准备:配置虚拟机网络
  • 计算机网络 --- 初识协议
  • 多人在线聊天服务器
  • P9235 [蓝桥杯 2023 省 A] 网络稳定性
  • Unity教程(十六)敌人攻击状态的实现
  • 【WebLogic】WebLogic 11g 控制台模式下的集群创建(一)
  • JetBrains系列产品无限重置免费试用方法
  • ATTCK实战系列-Vulnstack靶场内网域渗透(二)
  • Spring-bean的生命周期-中篇
  • 光伏开发:一分钟生成光伏项目报告
  • 大数据可视化-三元图
  • 【MySQL 04】数据类型
  • linux-安全管理-文件系统安全
  • 计算机组成原理(笔记4)
  • 八大排序——万字长文带你剖析八大排序(C语言)
  • python中数据科学与机器学习框架
  • device靶机详解
  • 【C++ 基础数学 】2121. 2615相同元素的间隔之和|1760
  • 音频3A——初步了解音频3A
  • 【Python语言初识(一)】