进程的概念
我们常见的计算机都遵循冯诺漫体系结构

当我们运行一个可执行程序的时候,开始程序会保存在磁盘上面,运行的时候,会加载到存储器上面,从而cpu进行处理。再返回存储器,再到输出设备。
为什么要先加载到存储器?
因为外设效率太慢,我们cpu不直接和外设打交道,要数据,只能从内存中读取。文件加载到内存上面是按需拷贝,然后cpu是读取地址,然后从内存上读取文件。
CPU 绝不直接等外设,必须让内存做缓冲。
程序运行之前,必须加载到内存。
CPU 不直接读外设,外设直接把数据丢进内存。
当我们在键盘输入泥嚎发送给朋友的时候,键盘小字节的内容直接拷贝加载到内存,
还有拉取文档给朋友,文档本身也在外设磁盘里面,加载 到内存,cpu读取,返回内存,再通过网络一系列发给朋友。
操作系统
什么是操作系统
操作系统是一个对软硬件管理的软件,它也是由c语言写的。
操作系统又分为广义操作系统(window操作系统加图形化界面+软件。linux加指令加shell命令行)
狭义操作系统☞的是操作系统内核。

为什么要有操作系统
操作系统对下进行软硬件管理(手段)。对上给用户提供良好的环境。
没有操作系统,计算机就无法正常的工作。
操作系统是如何管理的
操作系统对软硬件的管理。操作系统不能直接跟软硬件获取数据。要通过驱动程序获取数据,然后进行描述,在组织。
就像校长对于学生,不会当面一个从每个学生获取数据,而是通过辅导员来获取数据的.
先描述是什么?描述就是把被管理者的部分信息用结构体struct管理起来。为什么不用class(因为操作系统是用c语言写的)。
再组织是什么?就是对于每个个体,通过数据结构进行链接。完成对链表的增删查改。
(从而更好的管理,对于进程,我们可执行程序在磁盘硬件上,加载到内存,创建进程。进程就是对程序的描述,如何进行几个进程的组织,如果不执行该程序就会删除)
驱动就是翻译,操作系统和硬件之间的翻译。
什么是系统调用什么 是库函数
在开发⻆度,操作系统对外会表现为⼀个整体,但是会暴露⾃⼰的部分接⼝,供上层开发使⽤,
这部分由操作系统提供的接⼝,叫做系统调⽤。
•
系统调⽤在使⽤上,功能⽐较基础,对⽤⼾的要求相对也⽐较⾼,所以,有⼼的开发者可以对部
分系统调⽤进⾏适度封装,从⽽形成库,有了库,就很有利于更上层⽤⼾或者开发者进⾏⼆次开
发
为什么要有系统调用?因为直接让用户访问内核数据结构会存在安全问题。
系统调用也是唯一访问操作系统的接口。
我们使用的printf,等库函数也会封装系统调用,从而高效的访问操作系统。但并不是所有的库函数都有系统调用。
进程
进程的基本概念
进程在书本中被描述为加载到内存的就是进程。但真正的进程,是程序的属性被描述成take_struct,然后用数据结构链接起来。还有映射的代码。进程=内核的数据结构+程序的代码和数据。

进程是如何被管理的
对于程序,软件被操作系统加载到内存中,操作系统会把许多属性描述成为一个结构体放在内存。
它对于的代码(需要的时候才会映射)也会拷贝到内存。对于多个进程,操作系统是如果管理的,就是先描述,再组织。
take_struct内部描述的进程的属性。许多进程会被数据结构链接。所以操作系统对进程的管理变成了对链表的增删查改。

那进程内部的属性包含哪些:
标识符pid:: 描述本进程的唯⼀标⽰符,⽤来区别其他进程。
状态:任务状态,退出代码,退出信号等
优先级:对于cpu在调度的时候,进程相对于其他进程运行的优先级。
程序计时器:程序中即将被执行的下一条指令的地址。
内存指针:与程序代码和进程相关数据的指针。,还有和其他进程共享的内存块的指针
上下⽂数据: 进程执⾏时处理器的寄存器中的数据[休学例⼦,要加图CPU,寄存器]。
I∕O状态信息: 包括显⽰的I/O请求,分配给进程的I∕O设备和被进程使⽤的⽂件列表。
记账信息: 可能包括处理器时间总和,使⽤的时钟数总和,时间限制,记账号等。
其他信息
对内部属性的认识
pid和ppid:表示自己进程的标识符和父进程的标识符。怎么查找了?getpid(),和getppid()


当前进程一般ppid都是bash,注意先执行完前一条命令,再执行后一条命令要用&&,head -1这个是数字1.下面那个是grep code的进程
可以通过这个方式查看当前进程pid和父进程的ppid。
还有函数getpid(),getppid()。


当结束程序的时候,进程也会消失。

进程里面的属性

还有每次重新创建进程的时候,pid都会不一样。
什么是cwd?
进程属性的cwd是什么,其实就是当前进程的路径。为什么要cwd这个属性,当我们在程序读写文件的时候,如果没有这个文件,会在当前路径创建文件。这个cwd就是缺省路径


修改路径:


把路径复制放在cwd的数组里面。char*bf是存放char数组,或者字符串。
创建子进程(frok)



问题一:为什么给子进程返回0,给父进程返回子进程的pid.
因为需要唯一的标识符来识别进程,未来还有一个父进程:多个子进程。
问题二:为什么fork会有两个返回值。

创建子进程,先会拷贝pcb成为子进程,修改部分属性,比如pid,ppid。
问题三:为什么同一个变量n==0,又可以大于0.
对于父进程和子进程他们的数据,子进程是拷贝父进程的pcb,代码是共享的,数据是分开的,这就是进程具有独立性。不仅子进程具有独立性,不同的进程更是独立。




不同一个flag,虚拟地址一样,但是物理内存空间不同,写时拷贝。
进程状态

操作系统的状态示意图。就让我们一一来里了解。
状态就是进程task_struct内部的一个属性。
运行状态
再了解运行状态的时候,我们来了解一个东西。cpu在调用进程的时候,会在调度进程,从cpu获取调度队列。为什么进程会被双链表链接,还有调度队列。我们c语言不是一个结构体只能一种数据结构链接嘛。

知道调度队列的结构体的地址,那我们怎么获取里面的数据了。首先c语言中,我们可以通过 字节最小地址的位置来偏移获取其他地址。对于int知道最小的地址,再偏移3个,然后cpu会根据当前的字节序组合成一个完整的整数类型。
对于我们只知道调度队列结构体的地址怎么知道进程的其他属性了?这就需要我们用一个思维,对于进程开始的地址肯定不是从零开始。那如果我们假设开始从零开始的,再算到成员结构体的偏移度,再从结构体的地址减去偏移度。



结构体的地址(即 &struct_obj)就是结构体第一个成员的最小字节地址。
所以啊,内核这样做更有通用性,一个task_struct就可以属于双链表,又属于调度队列,还有其他数据结构。
我们把在调度队列的进程叫做运行状态。
阻塞状态
就是进程等待某种资源的时候,资源 没有就绪,cpu会让当前进程阻塞住,直到资源就绪。
列如,我们执行输入的程序的时候,键盘没有被摁下,直到键盘被摁下,进程才从阻塞进程调到调度队列。
进程的成员有运行队列,等待队列,所以当进程阻塞的时候,运行队列断开啦,等待队列链接。device里面也有等待队列,但是头节点,用于连接进程中的等待队列。
当遇到scanf的时候,会遇到阻塞,所以会把进程连接到键盘device的等待队列后面。通过进程成员的等待队列的结构体连接。

阻塞挂起和运行挂起
什么是阻塞挂起,就是一个进程被阻塞了,当是内存空间严重不足,进程也没有运行,它的代码和数据占用空间,所以在磁盘开辟一个swap空间。把代码和数据拷贝过去。然后把内存中的删除。
什么是运行挂起,当内存还是不足的时候,一个cpu只能运行一个进程,所以在调度队列的其他进程的代码和数据也可以放在swap区,当需要的时候再换入进来。
对于没有修改的代码可以不放在swap()区,可以直接删除,需要的时候在从磁盘的源文件拷贝。
linux进程状态、

睡眠状态(slepping)
对于一个程序等待某种资源然后继续被cpu调用。等待的过程叫睡眠状态(s)可以被中断,crtl+c;或者kill -9;

暂停状态(T)
暂停状态就是进程不符合要求的工作,os会暂停进程。
在介绍暂停状态的时候,我们先了解什么是前台进程,什么是后台进程。一个终端只能有一个前台组。当然子进程属于父进程的组,所以子父进程都可以是前台进程。前台进程就是状态后面加一个+号。

要从键盘读取为前台进程,所以它的父进程bash就是后台进程了,所以pwd,ls -l等指令就没有用。crtl+c可以结束前台进程。

为什么要有前后台进程?
因为前台进程接受键盘的数据。后台进程不需要数据,也能跑提高效率。
fg加编号可以把后台进程转换为前台进程。

当我们用gdb调试的时候,遇到断点就暂停了,是因为系统让进程处于暂停状态了
不可中断状态(disk sleep)
对于这种状态,当我们大量的io操作的时候,磁盘老,硬件出现故障的时候,就会出现这种状态持续永久。对于平常大量io的时候只会出现短暂的d。对于出现d 状态,如果长时间出现那么会出现坏盘等操作,因为d状态不能杀死。还会进行io操作。
僵死进程
对于僵尸进程是因为一个pcb进程因为进程完成结束或者进程退出。代码和数据会被回收,但是pcb里面的


会等着父进程来读取。如果父进程一直不来读取,进程会处于僵尸状态。进程都会有父进程。
如果进程没有被读取就会出现内存泄漏。因为pcb进程没有被读取。回收.
对于进程结束里面的malloc和new操作进程结束不会出现内存泄漏。但是对于一个软件都会死循环,我们如果没有malloc和free,不管是是前台进程还是后台进程一直malloc都会造成严重的内存泄露。所以我们要free和delete.
为什么linux没有单纯挂起状态?
因为对于可运行状态内存不足被交换到swap区,和等待某种资源,如键盘的输入。这种也会交换到swap区他们都是T状态.
孤儿进程
对于上面子进程退出,父进程没有来读取就会出现僵尸进程。对于孤儿进程则是子进程退出,父进程没有退出。父进程退出了,子进程还在。怎么办?


孤儿进程会pid为1的领养了之后。会变成后台进程。所以只能kill -9加pid来杀死进程。

被领养就是为了pcb里面的信息被读取,pcb不被读取。避免内存泄露。