提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录
前言
操作系统的知识补充
我们来理解一个用户操作接口:
进程的理解
进程的基本概念
描述进程-PCB
task_struct-PCB的一种
task_ struct内容分类
进程的task_struct本身内部的属性有哪些?
1、启动
查找 pid 的方式:
方法一:
方法二:
2、进程创建的代码方式
我们为什么要创建子进程?
总结
前言
世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!
提示:以下是本篇文章正文内容,下面案例可供参考
操作系统的知识补充
我们来理解一个用户操作接口:
举个例子:
年轻人去银行办理业务,因为是年轻人,能力比较强,知道怎么办理,就可以直接找工作人员去办理;而老年人属于弱势群体,对于这些不熟悉,此时银行的工作经理就来了,他会帮助老年人准备好各种各样的手续,所有资料都准备好了,然后再让柜台前的工作人员来办理。
系统调用接口是操作系统提供的,用户必须懂一点操作系统,才可以直接通过系统调用的接口来访问操作系统;而有的用户对操作系统不是很了解,操作系统提供的接口确实很难,这时可以通过用户操作接口,来访问系统调用接口 ----> 访问操作系统。用户操作接口(库,例如:c/c++标准库)是系统调用接口的封装。
代码不具有跨平台性根本原因:
你直接访问操作系统的系统调用接口,平台不同,操作系统不同,系统调用接口、返回值,函数名都不同,所以不具有跨平台性。
c/c++具有跨平台性:
在用户操作接口方面:linux下给c语言提供了linux版的库函数,在windows中给c语言提供了windows版的库函数,大家向上提供的都是printf函数;系统调用接口方面:linux用linux的系统调用接口帮助你向显示器打印,windows下用windows的系统调用接口帮助你完成向显示器打印。
进程的理解
struct PCB{}在操作系统中,我们一般给它叫做内核数据结构。
没开机的话,操作系统(OS)也是储存在磁盘当中的一个二进制文件。可执行程序没有运行起来的话,一般都在磁盘中。
开机的时候,操作系统是第一个加载到内存中的一个软件。内存数据块是在我们的操作系统内部的。
开机的时候,都要等上十几秒,是在磁盘中的操作系统加载到内存当中;然后当你创建进程时,一方面是把你的可执行程序和数据加载到内存当中,另一方面,需要在我们对应的操作系统内部malloc出来对应的结构体,你有几个进程,就malloc几个struct PCB{}
我们在整个操作系统内部里面对进程的管理,就变成了对struct PCB的操作。
我们可以转换成学校管理学生:
内存 ----->学校;操作系统 ------> 教务管理系统;学生 -----> 加载到内存中的代码和数据。
你怎么证明你是学校的学生呢?
你的属性信息(struct PCB)在学校的教务管理系统中。操作系统对于进程的管理,本质是对 struct PCB{}的管理,而并非是对你的可执行程序加载到内存之后,对可执行程序做管理。
为什么要有PCB呢?
OS操作系统要对进程做管理!!!任何管理:先描述,在组织
PCB是对操作系统学科里面所有进程控制块的统称。
Linux进程控制块的具体称呼:struct task_struct。
调度运行进程,本质就是让进程控制块 struct PCB{} 进行排队!!!
如何理解进程动态运行?
只要我们的进程task_struct,将来在不同的队列中,进程就可以访问不同的资源。
进程的基本概念
- 课本概念:程序的一个执行实例,正在执行的程序等。
- 内核观点:担当分配系统资源(CPU时间,内存)的实体。
描述进程-PCB
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
- 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct
task_struct-PCB的一种
- 在Linux中描述进程的结构体叫做task_struct。
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
task_ struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
进程的task_struct本身内部的属性有哪些?
1、启动
- 1、./xxxx,本质就是让系统创建进程并运行 ----- 我们自己写的代码形成的可执行 == 系统命令 == 可执行文件。在Linux中运行的大部分执行操作,本质都是运行进程!!!
- 2、每一个进程都要有自己的唯一的标识符,叫做进程 pid。
查找 pid 的方式:
方法一:
方法二:
一个进程,不通过ps指令,想知道自己的pid,该如何做呢?
用户不能对操作系统直接访问,要通过系统调用接口来进行访问,我们就学到了第一个系统调用接口 man getpid
- 3、ctrl + c 就是在用户层面上终止进程,kill -9 pid 可以直接用来杀掉进程。
2、进程创建的代码方式
父进程创建一个子进程,本质是系统多了一个进程,多了一个进程,就是多了:
1、内核 task_struct;2、有自己的代码和数据。
父进程的代码和数据是从磁盘加载来的,子进程的代码和数据呢?
默认情况继承父进程的代码和数据。
我们为什么要创建子进程?
我们想要子进程执行和父进程不一样的代码。
父进程创建一个子进程,创建一个进程是操作系统内多了一个进程,多了一个进程,其实就是多了一个struct PCB{}和该进程的代码和数据;创建一个进程就是创建一个struct PCB{}的内核数据结构,可是用户没有任何权利直接对内核数据结构(操作系统)进行任何的增删查改,所以为了创建进程,操作系统就得给我们提供一个系统调用接口(fork)。
fork()的返回值:
如果fork()函数成功了,会返回子进程的pid(pid > 0)给父进程,返回0给子进程;
如果fork()函数失败的话,-1就返回给父进程,没有子进程创建成功,错误码被设置。
fork()之后的代码,其实都被父、子进程共享的,只不过这里做了判断,子进程通过fork()进入子进程的执行流当中;父进程进入父进程的执行流当中。
父进程和子进程是并列的,退出谁,也不会影响另一个。
怎么理解fork()会有两个返回值,返回两次?
fork()是一个函数,是由操作系统(OS)提供的,fork()是一个系统调用接口。当我们执行到 return 的时候,函数是不是已经执行完了?执行到 return 的时候,子进程已经存在了,并且子进程可以被调度了,return 也是代码。我们之前说的 fork()之后,代码共享,这种说法不太准确,而是在fork()内部,前半部分代码由我们的父进程创建子进程,执行到 return 的时候,已经是两个执行流了,所以父进程被调度一次,子进程被调度一次,各自执行一次 return ,return 被执行两次。其实不是 fork()之后的代码,而是 fork()从后半部分代码和 return 之后的所有代码都是被大家共享的。
进程一定要做到:进程具有独立性。
进程 = 内核数据结构task_struct(父、子进程是独立的,有各自的 pid)+ 进程的代码(只读的!所以父子之间可以共享代码)+ 进程的数据(原则上:数据要分开,这个之后再细谈)
样例代码:一次创建多个进程
每个进程在启动的时候,会记录自己当前在那个路径下启动。
/根目录下有一个 proc 目录,proc 目录会不时地把内存当中的进程信息,给我们挂接到文件当中,让我们以文件的方式可以看到对应的进程的相关信息。
如果我们一个进程正在执行,我们把进程的可执行程序删除掉,但是进程依旧在运行,这是为什么呢?
因为这里的删除只是删除的是磁盘中的代码,而可执行程序已经加载到内存当中了,所以进程还是在运行,当然还要看程序的大小,当可执行程序非常大时,进程一开始还是好的,但是过一段时间后,进程会出错。
man chdir 更改一个调用进程的当前的工作路径。
总结
好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。