冯诺依曼体系结构
现代计算机的硬件体系结构—五大硬件单元 五大硬件单元: 输入设备:进行数据采集的设备,获取数据的设备,例如键盘 输出设备:进行数据输出的设备,例如显示器 存储器:典型设备内存(本质上内存也不是用来存储数据的,而是用来交换数据,缓冲数据的) 运算器和控制器:典型设备CPU中央处理器
内存的存储介质是一种易失性介质(RAM),断电则数据丢失,但内存的吞吐率非常高,适合做中间缓冲区带 磁盘的存储介质是一种非易失性介质(ROM),断电数据不会丢失,但磁盘的吞吐率比较低,如果直接和CPU进行数据交换,速度不匹配,CPU会长时间处于空闲状态,效率低下 当需要从硬盘读入数据到存储器的时候,硬盘属于输入设备; 当需要从存储器写出数据到硬盘的时候,硬盘属于输出设备;
我们写程序,就是告诉计算机什么时候控制那个设备进行什么样的操作 例如:微信聊天,键盘采集到数据,数据放入存储器,从存储器中取出数据到CPU进行处理,处理完毕之后把处理后的数据放回到存储器,控制存储器,将数据输出给指定的输出设备–网卡,网卡接收到数据之后将数据发送到网上。对方通过输入设备–网卡,从网络上接受数据,将数据放到存储器,CPU从存储器拿到数据处理之后放回存储器,控制器就存储器中的数据交给输出设备–显示器
操作系统
一个完整的操作系统包含内核+应用 计算机主机是由一堆硬件所组成的,为了有效的控制这些硬件资源,于是乎就有了操作系统的产生了,操作系统除了有效率的控制这些硬件资源的分配,并提供计算机运作所需要的功能(如网络功能)之外,为了要提供程序设计师更容易开发软件的环境,所以操作系统也会提供一整组系统呼叫接口来给软件设计师开发用喔!
[dev@localhost instructions]$ ls
hello hello.c hello.i hello.o hello.s makefile
[dev@localhost instructions]$ ./hello
hello linux
当shell加载和运行hello程序时,以及hello程序输出自己的消息时,shell和hello程序都没有直接访问键盘、显示器、磁盘或者主存。取而代之的是,它们依靠操作系统提供的服务。我们可以把操作系统看成是应用程序和硬件之间插入的一层软件,如果所示,所有应用程序对硬件的操作尝试都必须经过操作系统。 操作系统有两个基本功能: (1)防止硬件被失控的应用程序滥用; (2)向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。 操作系统通过几个基本的抽象概念(进程、虚拟内存和文件)来实现这两个功能。 如图所示,文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示。 系统调用接口:操作系统向上层提供的用于访问系统内核的接口 库函数:针对某个功能,使用大量的系统调用接口进行封装而成的函数接口 库函数和系统调用接口的关系:库函数内部实际上就是调用了系统调用接口完成功能。
进程概念
进程就是运行中的应用程序。 应用程序:程序员所写的代码程序 代码程序:一堆硬盘上的固定指令,运行程序就是让cpu去处理程序指令 运行程序:首先要将程序从硬盘上加载到内存中,cpu从内存的指定位置开始处理。 并发执行:循环一个个处理 并行执行:同时处理 CPU的分时机制:我们有多个程序同时运行,但CPU(单核)只有一个,也就意味着同一时间只能处理一个程序,CPU的分时机制就是,将CPU对于任务的处理进行划分,让每个程序的指令和数据在CPU上只运行一段很短的时间(时间片),这个程序时间片运行结束,则切换到下一个程序。时间片很短,只要切换足够快,宏观就会觉得是在同时运行。
问题:当CPU来回切换调度的时候,如何知道上次运行的程序运行到什么位置? 因为程序的切换调度运行的,所以我们的系统必须要知道每个程序要运行的代码和数据存放在哪里,并且知道每个程序切换时运行到什么位置了,从什么位置开始运行。实际上,操作系统对于每个运行中的程序都有一个描述信息,描述了当前程序在内存中的位置,以及切换时候的上下文数据,归根结底描述的是整个程序的运行信息,而这个运行信息就叫做pcb进程控制块,操作系统就是通过这个描述信息对程序进行调度管理的。 问题:进程是什么? 进程就是运行中的应用程序,或者说在操作系统的角度,进程实际上是对一个系统对于程序运行的动态描述,通过这个描述操作系统才能实现对程序运行的管理。 这个描述是进程控制块–pcb,在Linux下是一个task_struct结构体 描述信息概述:内存指针、上下文数据、程序计数器、进程状态、IO信息、记账信息…
进程状态
进程状态:告诉操作系统,如何去调度进程,让程序运行更加良好 课本上的描述:
- 就绪–拿到时间片就能运行的状态
- 运行–正在CPU上运行的程序
- 阻塞–当前不需要调度运行
Linux下的进程状态:
- 运行态-R:包含了就绪和运行,指的是正在运行的和拿到时间片就能运行的都是运行态
- 可中断休眠态:休眠态,一种暂时不需要被调度运行的状态(休眠可以被打断进入运行态,要么条件满足自动唤醒进入运行态)
- 不可中断休眠态:休眠态,一种暂时不需要被调度运行的状态(休眠是不可被打断的)
- 停止状态:一种能够被调度,但是什么都不做的状态
- 僵死态:进程运行退出了,但是资源又没有被完全释放的状态
僵尸进程:僵死态的进程,退出了但是资源没有完全释放的进程,是一种待处理状态 造成僵死态的原因:一个进程推出了,进程会有一个原因保存在pcb中,因此当进程退出后,pcb不能直接被释放,因为要保存退出原因,因此退出前通知父进程,但是父进程没有收到消息,因此这个进程就一直处于资源没有完全释放的待处理状态 僵尸进程危害:资源泄露(占据的内存没有完全释放,一个用户所能创建的进程数量是有限的) 如何退出僵尸进程:僵尸进程是杀不死的,把父进程杀死(因为子进程的退出原因就是给父进程保留的) 如何避免:进程等待 进程查看指令:
[dev@localhost processconcept]$ ps -ef
UID PID PPID C STIME TTY TIME CMD
...
[dev@localhost processconcept]$ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
...
杀死进程指令:
kill pid
kill -9 pid
[dev@localhost processconcept]$ kill -9 5940
运行状态,遇到某些操作条件不满足,进入阻塞状态(条件满足再来唤醒我运行),当cpu调度时,阻塞状态则查看条件是否满足,满足则置为运行状态,不满足则切换。 而可中断休眠是可以被打断的,一旦被打断,也进入运行状态 我们在终端运行的程序或者指令,他们的父进程都是shell–bash,而这个进程人家作为父进程是非常负责任的,一旦他的子进程退出了,立即就会去处理,因为咱们运行的程序退出了不可能成为僵尸进程
创建一个子进程:
pid_t fork();
功能: 通过复杂调用进程,实现创建一个一个新的进程。 进程就是pcb,Linux下是一个task_struct结构体,创建子进程就是创建一个新的结构体,复制父进程pcb中大部分信息(内存信息,上下文…),两个进程都会从创建子进程之后开始运行相同的代码 创建子进程的目的: 1.父子运行功能一样,在大量任务处理中,多人处理总比一个人来的快—分摊压力 2.让子进程运行另一段代码,也就是让父子进程功能不同 函数返回值: 1.在父进程中返回子进程的pid 2.在子进程中返回0 3.出错返回负数
环境变量
保存当前运行环境参数的一些变量,可以让环境配置更加简单,一个终端中配置的环境变量,在其他终端中并不生效,每个终端都有自己独立的运行环境,互不交叉。 PATH环境变量:保存系统的程序默认查找位置,将我们自己的程序所在路径加入其中,则我们运行自己的程序也就不需要路径 如果没有环境变量,则所有的配置,都在配置文件中,每当你修改了配置文件,就需要重新加载配置
//当前文件夹下有一个path,path的作用是ls
[dev@localhost processcontrol]$ ls
makefile path path.c processreplace processreplace.c wait wait.c
[dev@localhost processcontrol]$ path
bash: path: 未找到命令...
//配置环境变量
[dev@localhost processcontrol]$ PATH=${PATH}:./
[dev@localhost processcontrol]$ path //注意是path,而不是./path
总用量 52
-rw-rw-r--. 1 dev dev 72 5月 13 14:58 makefile
-rwxrwxr-x. 1 dev dev 8552 5月 13 15:03 path
-rw-rw-r--. 1 dev dev 81 5月 13 15:03 path.c
-rwxrwxr-x. 1 dev dev 8736 5月 13 15:00 processreplace
-rw-rw-r--. 1 dev dev 896 5月 13 15:00 processreplace.c
-rwxrwxr-x. 1 dev dev 8808 5月 13 14:42 wait
-rw-rw-r--. 1 dev dev 984 5月 13 14:45 wait.c
命令:
//查看所有环境变量
[dev@localhost instructions]$ env
...
//打印指定环境变量的内容
[dev@localhost instructions]$ echo $PATH
...
//查看当前环境中的所有变量(包括普通变量和环境变量)
[dev@localhost instructions]$ set
...
//设置一个普通变量
[dev@localhost instructions]$ MYVAL=10
[dev@localhost instructions]$ set|grep MYVAL
MYVAL=10
//export声明一个变量为环境变量
[dev@localhost instructions]$ export MYVAL=20
[dev@localhost instructions]$ set|grep MYVAL
MYVAL=20
_=MYVAL
[dev@localhost instructions]$ env|grep MYVAL
MYVAL=20
//unset移除变量
[dev@localhost instructions]$ unset MYVAL
环境变量和普通变量的区别:环境变量可以在进程之间进行自动传递,在程序中可以获取到当前环境的环境变量数据,但是获取不到普通变量的数据
|