Linux进程总结详解(上——初识)

Linux进程



前言——先从硬件和软件谈起

一、冯诺依曼体系结构

  1. 定义:数学家冯·诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成(运算器、控制器、存储器、输入设备、输出设备),这套理论被称为冯·诺依曼体系结构,如图:

在这里插入图片描述

输入设备:键盘、鼠标、网卡、显卡等等
输出设备:显示器,打印机等等
中央处理器(CPU):运算器和控制器等

需要知道的是——冯.诺依曼体系结构是现代计算机的基础
现在大多计算机仍是冯.诺依曼计算机的组织结构,只是作了一些改进而已,并没有从根本上突破冯体系结构的束缚。

二、操作系统

计算机是各种硬件构成的,那么这些硬件就需要软件去操控。

概念

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:

内核(进程管理,内存管理,文件管理,驱动管理)
其他程序(例如函数库,shell程序等等)

设计OS的目的
1.与硬件交互,管理所有的软硬件资源
2.为用户程序(应用程序)提供一个良好的执行环境

计算机软件和硬件之间的结构图如下:

在这里插入图片描述


一、进程介绍

概念

  • 课本概念:程序的一个执行实例,正在执行的程序等

  • 内核观点:担当分配系统资源(CPU时间,内存)的实体
    (包含着程序代码 + 相关数据结构)

    首先,程序就是我们所写的代码也就是一堆文字符号,而真正想要运行,得要和计算机软件硬件联系起来。按照课本上的定义,被加载到内存中的程序就叫做进程。而这些进程都是由操作系统来管理的。比如去分配资源比如时间片等等去进行各种调度策略这里我们不做赘述想要了解的同学可以去查查资料。

进程控制块

我们知道进程是由操作系统管理的,它管理的方式就是先描述再组织。我们知道linux操作系统是由C语言编写的,那么描述进程的结构就用的是结构体。描述进程的结构体也叫做PCB。

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。课本上称之为PCB(process control block),在Linux操作系统下则是一个结构体task_struct。具体可参考task_struct结构体结构
  • 在linux系统下,描述进程的结构体是task_struct,是内核的一种数据结构,会被加载到RAM(内存中)并且保存着进程的信息。
  • task_struct内容:
  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
    状态: 任务状态,退出代码,退出信号等。
    优先级: 相对于其他进程的优先级。
    程序计数器: 程序中即将被执行的下一条指令的地址。
    内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
    上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
    I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
    记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
    其他信息
    在这里插入图片描述

小结:一个程序想要运行的时候就会以进程的形式存在,当进程生成的时候,OS会给进程自动创建一个对应的PCB来管理进程。曾经我们运行各种程序的本质就是在操作系统上建立进程!!!


上边说完了描述进程,接下来说说怎么组织进程

进程的组织方式一共有三种:

  1. 链接方式
  2. 索引方式
  3. 连接表方式
    具体参考进程的组织方式,只需了解一下,本篇文章不做重点阐述。

如下图所示,在内存中多个进程都有自己的进程号id,一个进程是包含他的代码段和数据段以及相关的数据结构的。linux下task_struct中数据会保存对应进程数据和代码地址,而每一个进程之间也可以相互通信。
当CPU调度的时候,只需要提供给CPU ,PCB相关数据就会找到对应的进程去调度。
在这里插入图片描述

并且所有运行在系统里的进程都以task_struct链表的形式储存在内核里。

查看进程

  • Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。
  • 而系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的 PID号为目录名,它们是读取进程信息的接口
    在这里插入图片描述
  • 通过系统调用获取进程标示符
  • 进程id(PID)
    父进程id(PPID)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
 	printf("pid: %d\n", getpid());//打印该进程的id号
 	printf("ppid: %d\n", getppid());//打印该进程父进程的id号
 	return 0;
}

实践操作一下:

在这里插入图片描述

通过系统创建进程

  • fork函数
    fork系统调用用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进程称为父进程。创建新的子进程后,两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc(程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。
    它不需要参数并返回一个整数值。下面是fork()返回的不同值。

负值:创建子进程失败。
零:返回到新创建的子进程。
正值:返回父进程或调用者。该值包含新创建的子进程的进程ID

在这里插入图片描述
就是好比细胞分裂,父亲和孩子从fork();语句开始共享同一份代码和数据,并且都向下执行。(相当于两个程序一起跑)
当然一个父进程也可以有多个子进程

这里要注意fork函数有两个返回值,一个是父进程的返回值,返回子进程的id。二是子进程的返回值,正常返回0,错误返回一个负值。
调用fork之后,数据、堆、栈有两份,代码仍然为一份但是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。

引用一位网友的话来解释fork函数返回的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fork函数返回的值指向子进程的进程id, 因为子进程没有子进程,所以其fork函数返回的值为0.

具体参见fork百度百科

举例如下,用if语句判断fork函数返回值不同区别父子进程,来执行不同代码,可以看到最后父进程返回值是子进程的ID,子进程返回0.
在这里插入图片描述

二、进程状态

1.内核代码如下:

一个进程可以有几个状态(在linux内核下进程也可以叫任务)

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): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
    (interruptible sleep))。
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的
    进程通常会等待IO的结束。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

总结

本篇文章带你了解进程初识,了解进程已经父子进程的概念。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李 天 真

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值