文章目录
一、冯诺依曼体系结构
我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。
计算机包含输入设备、输出设备、存储器、中央处理器(运算器+控制器)
至目前,我们所认识的计算机,都是有一个个的硬件组件组成。
磁盘属于外存,具有永久性存储能力。
CPU作为计算机的核心,负责计算,速度最快,寄存器次之,内存在次之,而外设是较慢的。
但是CPU只能被动接受别人的指令和别人的数据,那么CPU必须先认识别人的指令(每个CPU被制作都有自己的指令集),才能执行别人的指令,起到计算别人数据的目的。
上面说到CPU的速度很快,而外设的速度很慢,那么CPU直接从外设拿数据效率就降低了,所以数据是从外设加载到内存中的,然后CPU再从内存中读取数据,CPU处理完的数据再返回给内存(产生了缓存),数据再从内存中加载到外设,这大大提高的数据的处理。
所以CPU再读取和写入时候,在数据层面只和内存打交道,为了整体效率。
内存从外设读取和写入数据的过程成为I/O过程(input/output)
对于冯诺依曼体系,我们应该注意:
所以程序的运行必须要加载到内存,CPU执行的代码访问数据,只能从内存中读取(这也是体系结构规定的)。
对冯诺依曼的理解,不能停留在概念上,要深入到对软件数据流理解上,请解释,从你登录上qq开始和某位朋友聊天开始,数据的流动过程。 从你打开窗口,开始给他发消息,到他的到消息之后的数据流动过程。如果是在qq上发送文件呢?
二、操作系统OS
- 是什么
操作系统是一个进行软硬件资源管理的软件,操作系统包含了进程管理,文件管理,内存管理,驱动管理。
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
- 为什么
操作系统通过合理的管理软硬件资源(手段),为用户提供良好的,稳定的,高效的,安全的执行环境(目的)。
在整个计算机软硬件架构中,操作系统的定位是: 一款纯正的“搞管理”的软件
- 怎么办
- 管理者不需要与被管理者直接交互,依旧能够很好的将被管理者管理起来
- 管理的本质是对数据进行管理
- 管理的方法是先描述,再组织
所有的管理,本质是对数据做管理,管理的方法是先描述在组织
计算机管理硬件
1.描述起来,用struct结构体或者类
2.组织起来,用链表或其他高效的数据结构
总结:
三、系统调用和库函数概念
系统提供调用接口原因:操作系统不相信任何用户 – 操作系统不确定我们是否会对各种软硬件进行违法操作。但是操作系统又必须给上层用户提供各种服务,于是 给用户提供系统调用的接口,即当用户有访问软硬件的需求时,直接调用操作系统提供的接口,然后由操作系统来帮助用户完成对应的工作;这样即满足了用户的需求,又保护了软硬件资源。
四、进程
1.概念
也有书籍是一个运行起来(加载到内存)的程序时进程。
进程和程序相比进程具有动态属性。
而程序的本质计算文件,存储在磁盘中。
2.描述进程-PCB
当大量的程序加载到内存中,,操作系统用进行管理,会对程序进行先描述,在组织。
而描述进程-PCB
//进程控制块
struct task_struct3
{
//该进程的所有属性
struct task_struct* next;
//该进程对应的代码和属性的地址
}
组织:对进程管理变成了进程对应的PCB进行相关的的管理。而对进程管理转化成了对链表的增删查。
struct task_struct* p1 = malloc(struct task_struct);
p1->..=xx;
p1->addr = 代码和数据的地址;
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
- 课本上称之为PCB(process control block), Linux操作系统下的PCB是: task_struct
先描述,再组织工作 : struct task_struct内核结构体 --> 内核对象task_struct 对象 --> 将该结构体,代码和数据关联起来。
所以 进程 = 内核数据结构(task_struct) + 进程对应的磁盘代码
- 程序和进程
程序的本质是放在磁盘上的可执行文件(.exe文件),就是一个文件,根据冯诺依曼体系,软件运行要加载到内存中,而进程则是将程序加载到内存当中,并且由操作系统进行管理,生成一个描述自身性质的数据结构(PCB),由内核数据结构和进程对应的磁盘代码两者共同组成“进程”
- task_struct
task_struct-PCB的一种,在Linux中描述进程的结构体叫做task_struct。task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息 。
可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。
- task_ struct内容分类
3.查看进程
首先创建一个死循环文件,方便查看进程:
make一下,生成可执行程序,开始执行:
接下来可以查看进程:
进程的信息可以通过 /proc 系统文件夹查看
如:要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹
大多数进程信息同样可以使用top和ps这些用户级工具来获取
ps ajx | grep "myproc"
ps ajx | head -1
ps ajx | head -1 && ps ajx | grep "myproc"
同时,我们可以杀掉(kill)进程,当然ctrl+c也可以直接结束掉:
kill -9 进程PID
进程在调度运行的时候,进程就具有动态属性。
进程在运行的时候本质是在读取进程内部的代码,内部在执行,从启动到终止中间可能会有一段很长的时间,这个进程就具备了动态属性。
查看进程:
ls /proc/
4.查看系统调用
- getpid()
man 2 getpid
如果指令无法实现,则要下载:
sudo yum -y install man-pages
获取进程PID需要两个头文件,调用响相应函数,最后的返回值就是进程的PID
对myproc.c进行修改:
运行并查看进程:
此外,还有另一种方法查看进程:
在Linux中proc是内存级目录
ls /proc/
数字开头就是进程的pid,一个进程也可以当做文件来看待
ls /proc/进程PID -d
如果程序被删除了,那么进程还会跑吗?
可以看到进程依然可以跑。
5.查看进程调用
- getppid()
获得父进程ID
man 2 getppid
- 创建文件
touch myproc.c
tpuch Makefile
- 运行停掉
可以看到每次进程运行的时候,子进程的ID是变的,父进程的ID不变。 - 查看父进程
ps axj | head -1 && ps axj | grep 父进程PPID
命令行上启动的进程,一般它的父进程没有特殊情况的话,都是bash
以子进程方式运行,遇到问题只与子进程有关,与父进程无关。
6. 通过系统调用创建进程-fork初识
- fork
make fork
- fork第一种用法
运行
fork是一个函数,用于创建子进程,函数执行前只有一个进程,函数执行后有两个进程:父进程和子进程,即打印两条。
即前一个进程的子进程是后一个进程的父进程。
- fork第二种用法
fork()返回类型是 pid_t
同一个变量id,在后续不被修改的情况下,竟然有不同的内容。
(所以对于结果我们很好理解,返回成功时,会给父进程返回子进程的pid,子进程会返回0)。但是,这里居然一个变量id居然会有两个返回值。我们根据这个返回结果写代码:
我们可以看到,两个while循环都执行起来了,这也证明了实际上参与while循环的有两个进程!并且它们是父子进程,即父子关系。
这也说明了,在fork之后,又创建了一个进程,两个进程分别在两个执行流中,因此可以分别执行if 和 else if,也可以分别进入while循环!
总结一句话,fork()之后,会有父进程+子进程两个进程在执行后续代码,fork()后续的代码,被父子进程共享,通过返回值不同,让父子进程执行共享代码的一部分,这就是并发式编程。