菜鸟笔记
提升您的技术认知

Linux进程概念(一)

Linux进程概念(一)

  • 1.冯诺依曼体系
  • 2.操作系统(OS)
  • 3.进程
    • 3.1查看进程
    • 3.2父子进程
    • 3.3如何创建子进程

1.冯诺依曼体系

我们这里的存储器一般指的是内存,输入输出设备称之为外围设备,外设一般都会慢一些,因此需要内存
不考虑缓存的情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入和输出设备)
外设要输入或输出数据,也只能写入内存或者从内存中读取
所有设备都只能直接和内存打交道
因为有了内存的存在,我们可以对数据做预加载,CPU以后在进行数据计算的时候,根本不需要访问外设了,而只要直接向内存要就可以啦

2.操作系统(OS)

设计OS的目的:与硬件交互,管理所有的软硬件资源;为用户提供一个良好的执行环境

上图就是一个计算机软硬件体系结构,操作系统也是一个软件
1.描述起来,用struct结构体,软件和硬件都是这样的
2.组织起来,用链表或者其他高效的数据结构
3.操作系统通过驱动程序管理底层硬件
4.在开发角度,操作系统会对外表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口叫做系统调用,其实本质就是C函数,因为Linux底层是用C语言写的
5.系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以有心的开发者可以对部分系统调用进行适度封装,从而形成了库。由于系统调用过于复杂,因此出现了图形化界面,shell和工具集

3.进程

进程就是内核关于进程的相关数据结构和当前进程的代码和数据
进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性集合。
课本是称之为PCB(process control block),Linux操作系统下的PCB是task_struct
tast_struct是PCB的一种

3.1查看进程


大家可以看到,有非常的进程,哪如何查看他呢?
使用命令ps axj
接下来我们写一个基本的C代码,来执行,看看是否会出现在进程列表中

因为就一个打印语句,运行很快,我们查看不到,所以说使用死循环来进行运行

可以和grep和head配合使用,把第一行的说明和有我的可执行程序的进程信息打印出来

因为grep也是进程,想要去掉他后面就再加一条命令


实际上之前介绍Ctrl+c就是结束进程的意思
不过现在要重点来看一下进程的信息

pid其实就是进程的标识符,用来辨别每个进程,他可没有那么简单,他还有很多内容需要探索

可以尝试一下多次启动C程序,可以发现他的pid每次都是不一样的,但是程序每次都是同一个,实际上就相等于,你考了一所学校,你的学号是1号,但是你并不喜欢这所学校,因此你退学了,但是很不幸,你又考上了这所学校,但这次你的学号是9。这个pid可能在你程序结束后,别人在用了,因此每次的pid都可能是不一样的
这里给大家再介绍一个可以查看进程的方式,在我们的根目录下有一个proc目录,这个目录里面都是进程的信息。

接下来,我们把进程终止掉,看看会发生什么

可以发现我们原本还在这个进程的目录里面,终止掉进程后,连目录也找不到了,其实也得出了结论,当进程终止的时候,为这个进程创建名为其pid的目录就会被销毁

3.2父子进程

其实在我们的进程中,还有父进程,子进程这样的概念,接下来我们就详细看看


我们需要使用的是getpid和getppid两个系统函数,可以通过man手册来查看
其中,他们的返回值本质上就是有符号的整形,没有参数,但是需要头文件,通过使用他们可以获取对应的pid和父pid
接下来我们就来使用一下他


可以看到他的父进程的pid是32615,那他是谁呢?

bash?bash是什么呢?
实际上他就是我们的命令行解释器
①bash命令行解释器本质上他也是一个进程
②命令行启动的所有的程序,最终都会变成进程,而该进程对应的父进程都是bash

3.3如何创建子进程

首先要先介绍一个函数,fork

fork的返回值:当执行父进程的时,返回子进程的pid,当执行子进程时,返回0


我们能发现,明明代码里只有一条打印语句,却打印了两条,这是fork的作用。
在打印出来的内容中,可以看到第二条的父进程的pid就是上一条的pid,说明创建了子进程,但是有个奇怪的问题,为什么,明明同一个变量ret会打印出不同的值,而且地址还是相同的?
①fork之后,执行流会变成两个执行流
②fork之后,谁先运行由调度器决定
③fork之后,fork之后的代码共享,通常我们通过if和else来进行执行流分流

其实进程在运行的时候,是具有独立性的,就和我们windows下的一样,你关闭了qq会影响其他的软件的运行吗,并不会,那么父子进程运行的时候也一样。
父子进程对于代码是只读的,而对于数据而言,当有一个执行流尝试修改数据的时候,OS会自动给我们当前进程触发写时拷贝。
而为什么fork的返回值会有两个呢,其实在我们函数内部准备执行return的时候,我们的主体功能已经完成,也就是说在fork函数return的时候,子进程已经创建好了,父子进程会返回各自的返回值,当给到变量ret时,会发生写时拷贝。