进程
进程:加载到内存的程序就叫做进程(书本)。
任何进程形成时,操作系统要为该进程创建PCB(进程控制块)。
这个PCB可以理解为是一个结构体,里面存放的时进程的相关属性
struct PCB{
//进程的所有属性
}
进程的查看
我们写一个每间隔两秒打印一句hello linux的程序
我们可以使用ps命令去查看进程
这样我们能查看到我们的所正在进行的进程,其中PID为描述进程的唯一标识符
linux会默认给一个查看进程给的目录/proc
在有一个进程时,这个进程会在/proc目录下以自己的PID创建一个进程文件夹,进入进程文件夹中都有一个cwd目录为(当前工作目录)。
PCB的内部构成
- 标识符(PID):描述进程的唯一标识符。这里的PPID为该进程的父进程的PID。
- 状态:任务状态退出码等信息
- 优先级:相对于进程的优先级
- 程序计数器:程序中即将被执行的下一条指令的地址。
- 内存指针:可以通过PCB找到进程的代码
- 上下文数据:进程执行时处理器中的数据
- I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息:可能包括处理器时间总和,使用的时钟总和,时间限制,记帐号等等。
上下文数据的理解
CPU一次只能执行一个进程,我们看到的我们电脑上运行的多个进程本质上是通过CPU的快速切换完成的,那么在运行期间是有切换的,那么进程可能存在的大量的临时数据,这些临时数据在CPU寄存器中保存。
假设我们一个进程在CPU上跑了10ms,之后就会被替换下来换一个进程上去,这个进程假设再运行10ms,那么在替换的过程中,第一个进程没有跑完,等一下还要继续运行,上下文数据可以理解为这次这个进程跑到哪里了,以便于下次使用CPU资源的时候可以继续接着运行。
通过上下文数据的保护和恢复,我们可以感受到进程之间切换。
通过系统调用创建进程fork
fork是通过系统调用来创建一个与原来的进程几乎完全相同的进程,基本上两个进程做的事情是相同的,但是当我们为两个进程传入不同的参数的时候,这两个进程也可以做不同的事。因此fork()的本质是用来创建进程。
当我们将上面的代码运行起来之后
只有一行打印,但是打印出来了两行内容,我们可以看到第二行的父进程就是第一行。因此这里证明了fork()确实可以创建进程,但是我们难道就是为了创建进程来干一样的事情吗,当然不是,这样是没有意义的,我们可以通过if else分流,来让父子进程做不一样的事情。
我们看到这两个代码同时运行了我们是通过fork的返回值来控制的
如何理解有两个返回值?
如果一个函数已经开始return了,函数的核心功能已经执行完了。返回值是一个数据,return时会写入,发生了写时拷贝。
如何理解fork()创建子进程
无论是命令创建进程,还是fork()创建进程,在操作系统的角度来看,他们创建进程的方式是没有差别的。for()的本质是创建进程,创建了进程之后系统里就多了一个进程,这个进程包含了与进程相关的内核数据结构和进程的代码和数据在系统里多了一份。我们创建的子进程在默认情况下会“继承”父进程的代码和数据。也就是说子进程和父进程的代码时共享的,在默认情况下,数据也是共享的,但是要考虑修改的情况。进程是具有独立性的,无论是不是父子进程,我们的父子进程是通过一种写时拷贝的技术来完成进程数据的独立性。
fork()的返回值类型为pid_t。