我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。
截至目前,我们所认识的计算机,都是由一个个的硬件组件组成
再次强调: 程序运行时必须先从磁盘加载到内存,CPU获取写入只能从内存中拿数据,CPU执行我们的代码,访问我们的数据,数据从一个设备“拷贝”到另一个设备 体系结构的效率:由设备的拷贝效率决定 结论: CPU在数据层面只和内存打交道,外设只和内存打交道
由于外设的速度比较慢,CPU的速度较快,所以外设和CPU之间就存在木桶原理,内存的出现让CPU和外设的速度更匹配。 冯诺依曼体系结构的存在使得电脑变便宜了。
两个人如果在微信上面聊天,本质上是两个冯诺依曼体系之间的信息流通,发信息的人通过输入设备“键盘”进行输入。我们发微信首先得打开登陆微信,即把微信的可执行程序加载到内存。所以在键盘里输入根据冯诺依曼体系是把键盘数据搬到内存(硬件层面),软件层面是把数据交给微信 ,所以数据流动就从输入数据流到存储器。微信信息比如说要加密,把数据“你好”(发送的数据)经过运算器控制,运算器运算完毕之后把“你好”转化成了一个乱码的结构,然后再有CPU
写入内存,再由微信把你自己的数据传输到输出设备 ,用户a
的输出设备是网卡,网卡把数据交到网络里,通过网络再把数据交给用户b
。用户b
的输入设备拿到数据,而用户b的输入设备只能是网卡,输入设备拿到数据放到内存里,用户b
也必须启动微信,启动的微信也在内存里,在微信里读到的代码再交给CPU
,将乱码数据解密成“你好”,再通过存储器刷新到输出设备上,这个输出设备就是显示器。
那如果是发送文件呢???
其实文件的本质也是数据,当我们把文件拖到微信程序时,在没拖之前文件是在磁盘上,本质上是把磁盘文件拷贝到微信里面,在经过运算器加密包装回到存储器,在经过网卡发送,对方通过网卡接受,接收后首先要把文件数据读到内存,通过运算器解包解密写回内存,然后把数据写到输出设备。
总结:
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
操作系统本质是一款进行软硬件管理的软件
操作系统上面不仅有硬件,而且还有软件
操作系统就如同校长一样具有决策权
,驱动程序就如同辅导员具有执行权
,底层硬件就如同学生被管理
📌:操作系统通过数据对底层硬件进行管理,而数据是通过驱动程序获取的。 总结: 计算机管理硬件
先描述,后组织
struct
类对象,然后把进程相关的属性放在结构体里,用链接节点连起来,对进程管理转化成对链表的增删查改。操作系统不相信任何用户或者人,操作系统要向上提供对应的服务,就好比“银行”
操作系统会把自己封装起来,所以系统调用本质上是操作系统提供给我们的系统调用。我们未来在操作系统获取信息等都是通过系统调用完成的。 系统调用的本质是用户和操作系统之间进行某种数据的交互。 结论:
因为操作系统内同时可能有许多的可执行程序加载到内存里,所以必然要对加载到内存中的程序做管理,答案是先描述(给每个可执行程序定义结构体(PCB)Liunx下叫struct task_struct
进程控制块),与下一个可执行程序的结构体形成链表,这个链表就叫做进程列表
进程 = 内核数据结构对象 + 自己的代码和数据 进程 = PCB(task_strcut)+ 自己的代码和数据
✏️对进程的管理就变成了对链表的增删查改
✏️进程的所有属性都能直接或者间接在task_struct
找到
基本概念
PCB(process control block)
,Linux操作系统下的PCB是: task_struct
task_struct-PCB的⼀种
task_struct
。task_struct
是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。内容分类
组织进程
可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct
链表的形式存在内核里。
1.首先我们来自己创建一个进程,我们首先来认识一个进程指令getpid
我们历史上执行的所有指令,工具,自己的程序,运行起来全部都是进程!! 2. 写一个可以查看进程的程序
3.运行程序
4.只要是一个程序我们就可以查看它的进程,但是还不够,我们再打开一个Xshell
。在系统上我们有对应的指令让我们去查看当前的进程有哪些。这个指令就叫做ps
,我们可以查所有的以特定格式显示的进程,比如ps axj
其中的a
表示所有进程的意思。
这展现的就是系统中所有的进程。
5. 我们若只想查看我们自己刚刚的进程呢?ps axj | grep myprocess
Linux中我们也可以两条指令同时输入,用;
隔开,表示先执行前面的,再执行;后面的。出了这种写法我们也可以ps ajx | head -1 && ps ajx | grep myprocess
,效果和上面一模一样
6. 当我们查进程时会发现这个grep
一直存在,为什么呢?我们在查进程的时候grep
也是个命令,当它把显示出来的结果做过滤的时候,grep
命令一旦跑起来,它自己也是个进程,而它自己过滤关键字里本来就包含myprocess,所以它也会自己把自己查出来,我们如果不想看到grep
呢,我们可以ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep
,grep -v
表示反向匹配,包含grep
的不要,不包含的留下来了
7. 只要是个进程,我们就可以杀掉它,如何杀呢?ctrl + c
/kill -9 + pid
,杀掉进程。(-9
表示一个信号编号)
第二种查看进程的方式:
/proc
系统文件夹查看(以文件的形式查看进程)
每一个数字目录代表特定进程的pid
,每个目录包含的内容是这个进程运行时的动态属性
如:要获取PID为3908132的进程信息,你需要查看
/proc/3908132
这个文件夹。
3908132
文件夹中的内容
在重重之中,我们只需要了解两个
top
和ps
这些用户级工具来获取
上面中我们还遗留了一个信息getppid
,表示获取父进程Pid
下面我将讲如何不用指令而用代码创建进程,Linux中所有的进程都是被它的父进程创建的,Linux是一个单亲繁殖系统,只有父进程,没有母进程,所以Linux中所有的进程是一个进程树
运行
重新执行多次
我们看到的现象是他们的父进程都是一样的,那父进程是谁呢?
我们查到的父进程是一个bash
,叫做命令行解释器,本质是一个进程,我们每次登陆我们的云服务器,操作系统会给我们每一个用户分配一个bash
,-
表示远程登陆。
它先启动“printf”
打印命令行,然后再“scanf”
我们历史上执行的命令,比如ls
,pwd
,mkdir
都是进程,他们的父进程全都是bash
fork
是一个系统调用
正常情况下代码刚开始运行都是一个执行流,执行完fork
就会变成两个执行流,这两个执行流都会执行后续代码,这就是为什么进程开始运行
会出现两次,原因是进程 = PCB + 自己的代码和数据,父进程再创建子进程的时候会把它的PCB拷贝一份给子进程(但子进程pid会被修改),所以子进程的代码和数据和父进程的一样,所以会运行两次,子进程没有自己的代码和数据,因为目前没有新的程序加载,所以会共享父进程的代码和数据。
运行结果
fork
的返回值
这里提出几个问题:
fork
给父子返回各自夫人不同返回值?
父:子 = 1:n,因为父进程有多个孩子,一定要把子进程的pid
返回给父进程,父进程才好区分子进程return
,这个函数的核心功能已经做完了
写时拷贝:
独立性是如何做到的?数据结构独立,代码共享(代码是只读的,不影响),数据以写时拷贝的方式各自私有一份
pid_t id
这个变量