> 作者简介:დ旧言~,目前大二,现在学习Java,c,c++,Python等
> 座右铭:松树千年终是朽,槿花一日自为荣。
> 目标:了解冯诺依曼体系结构与操作系统,掌握Linux的进程
> 毒鸡汤:一花凋零荒芜不了整个春天,一次挫折也荒废不了整个人生。
> 望小伙伴们点赞👍收藏✨加关注哟💕💕
🌟前言
我们最初学习Linux指令已经可以用户与操作系统交互了,往后面我们用Xshell可以编写一些简单的代码,这些只能算是入门,咱们学习Linux可不是这些,如果只学习这些的话,那在C语言中这些我们已经掌握的比较熟练了😏😏。学习Linux掌握的是各种代码底层是如何运行和使用的。
⭐主体
我们从以下学习冯诺依曼体系结构与操作系统及其进程🤗🤗。
🌙冯诺依曼体系结构
冯·诺依曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同,如英特尔公司的8086中央处理器的程序指令和数据都是16位宽。
数学家冯·诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成(运算器、控制器、存储器、输入设备、输出设备),这套理论被称为冯·诺依曼体系结构。
截至目前,我们所认识的计算机,都是有一个个的硬件组件组成:
- 输入单元:包括键盘, 鼠标,扫描仪, 写板等
- 中央处理器(CPU):含有运算器和控制器等
- 输出单元:显示器,打印机等
关于冯诺依曼,必须强调几点:
- 这里的存储器指的是内存
- 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)
- 外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。
- 一句话,所有设备都只能直接和内存打交道。
这里说的光用文字是很难理解冯诺依曼体系结构的,大家可搜说相关图片用图来了解冯诺依曼体系结构。
🌙操作系统原理
什么是操作系统:
- 操作系统(英语:Operating System,缩写:OS)是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序。 根据运行的环境,操作系统可以分为桌面操作系统,手机操作系统,服务器操作系统,嵌入式操作系统等。
为什么要有操作系统:
- 手段:对下管理好软硬件资源。
- 目的:对上提供一个良好的运行环境-->(为用户提供稳定的、高效的、安全的、的执行环境)
用图解释操作系统:
操作系统本质对数据做管理,而管理的模用一句话来概括:先描述,在组织。
总结:
计算机管理硬件
- 描述起来,用struct结构体
- 组织起来,用链表或其他高效的数据结构
🌙系统调用和库函数
系统调用和库函数概念描述:
- 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
- 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。
那在还没有学习进程之前,就问大家,操作系统是怎么管理进行进程管理的呢?很简单,先把进程描述起来,再把进程组织起来!
🌙进程
💫概念描述
课本概念:程序的一个执行实例,正在执行的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体。
💫描述进程-PCB
进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。课本上称之为PCB(process control block), Linux操作系统下的PCB是: task_struct。
- task_struct
task_struct-PCB的一种,在Linux中描述进程的结构体叫做task_struct。task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息 。
- task_ struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
💫查看进程
说实话,文字干巴巴,想必大家看困了,这里我们简单模拟一下进程,看看进程到底是个啥吧🥱
首先先创建文件:
- Makefile:
- myproc.c:
运行结果:
查看进程:
使用 ps ajx (a:所有,j:任务,x:把所有的信息全部输出)
一般搭配管道进行使用,如:ps ajx | head -1 && ps ajx | grep test
,其中 ps ajx | head -1
是把 ps ajx
输出的信息中的第一行信息(属性列)输出。
💫通过系统调用获取进程标示符
我们可以用以下查看当前目录下的进程:ls /proc/
那我们如何查看我们的进程???
- 进程id(PID)--->getpid()
- 父进程id(PPID)--->getppid()
运行结果:
ps ajx | head -1 && ps ajx | grep "mypro" //查看自己的进程
💫通过系统调用创建进程-fork初识
再次修改我们的myproc.c文件
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { int ret = fork(); if(ret < 0){ perror("fork"); return 1; } else if(ret == 0){ //child printf("I am child : %d!, ret: %d\n", getpid(), ret); }else{ //father printf("I am father : %d!, ret: %d\n", getpid(), ret); } sleep(1); return 0; }
运行结果:
用下面指令搜索自己的进程:ps axj | grep 1889
那我们如何查看子进程和父进程交替呢???
- 我们再次修改myproc.c
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { printf("before fork: I am a prcess, pid: %d, ppid: %d\n", getpid(), getppid()); sleep(5); printf("开始创建进程啦!\n"); sleep(1); pid_t id = fork(); if(id < 0) return 1; else if(id == 0) { // 子进程 while(1){ printf("after fork, 我是子进程: I am a prcess, pid: %d, ppid: %d, return id: %d\n", getpid(), getppid(), id); sleep(1); } } else{ // 父进程 while(1){ printf("after fork, 我是父进程: I am a prcess, pid: %d, ppid: %d, return id: %d\n", getpid(), getppid(), id); sleep(1); } } sleep(2); return 0; }
- 运行结果:
fork()之后,会有父进程+子进程两个进程在执行后续代码,fork()后续的代码,被父子进程共享,通过返回值不同,让父子进程执行共享代码的一部分,这就是并发式编程。
🌟结束语
今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。