进程是现代计算机体系的重要概念,了解进程前必须知道计算机的运行方式与操作系统这两个概念(本文仅做概念引入,若想深入了解可以阅读《计算机导论》)
冯诺依曼体系结构让我们知道计算机的核心是CPU,它承担了所有的计算任务;
而操作系统就是计算机的管理者,负责任务的调度,资源的分配和管理;
为了在计算机上实现某种功能,程序员设计了一系列运行在操作系统上的应用程序;
从微观上看,这些程序在计算机上运行的就是一条一条带有某种使命的进程。
当今计算机运行的基本方式都是建立在冯诺依曼体系结构之上。
所谓冯诺依曼体系,就是将计算机分为了五个部分:CPU(运算器、控制器)、储存器、输入、输出设备;
注:这里的储存器指内存,而非硬盘.
并提出了计算机制造的三个原则:
一个用户无法直接与计算机硬件打交道,必须有个有一个 中介 方便用户对计算机的使用,这个中介就是操作系统(OS);
操作系统本质上就是一个协调、管理和控制计算机硬件资源和软件资源的控制程序;
因此我们也可以简单的认为:
操作系统 = 操作系统内核 + 应用
内核:指计算机中进行进程、文件、内存、驱动管理的程序
应用:附加在OS上为了实现用户目的的一些软件应用
由定义可知,操作系统就是一个管理计算机软硬件资源的软件。
硬件资源:CPU、内存、硬盘、IO接口…
软件资源:进程资源、驱动程序…
这里引入 进程 的概念,计算机执行一项任务的基本单位就是进程。大量进程在计算机中运行,就必须要协调管理,这个任务就是OS要做的事。
OS管理进程方式:描述 + 组织
进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体.
进程控制块(process ctrl block)是操作系统为了管理进程设置的一个专门的结构体 task_struct。
操作系统用它来记录进程的外部特征,描述进程的运动变化过程。同时,系统可以利用PCB来控制和管理进程。
那么进程控制块(即 task_struct结构体)都包含了哪些信息?
Linux中查看进程:
例:
#include
#include
int main()
{
while(1)
{
printf("my pid is %d\n",getpid());
sleep(3);
}
return 0;
}
就绪(Ready)状态
进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行
执行(Running)状态
进程已获得CPU,其程序正在处理机上执行
阻塞(Blocked)状态
正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。
引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
进程的并发与并行
对于单核操作系统,微观上其实做不到同一时刻多个进程同时执行。
但是OS通过对多个进程切换使用CPU资源,达到宏观上的同时执行,这就是并发。
对于多核操作系统,多个CPU同时执行不同的进程就是进程的并行。
什么是抢占式执行?
对于单核系统来说,一台计算机只有一个CPU,其同一时刻能够处理的进程只能有一个,因此每个进程都是抢占式执行:一旦运行条件满足就立刻执行;
而操作系统就是通过进程的状态来协调哪个进程执行或等待。一个进程在运行期间,不断地从一种状态转换到另一种状态,它可以多次处于就绪状态和执行状态,也可以多次处于阻塞状态。
现代OS对进程状态的划分不止上述三种,更加的具体:
运行状态(TASK_RUNNING):运行态和就绪态的合并,表示进程正在运行或准备运行。
要想观察一个进程的运行状态,就不能让这个进程return 0,因此可以为进程加一个while死循环;但是注意,这个循环内不能有sleep(),因为一旦调用了sleep,进程就可能处于水睡眠状态
可中断睡眠状态(浅度睡眠)(TASK_INTERRUPTIBLE):进程正在睡眠(被阻塞),当等待资源到来时即可唤醒,也可以通过其他进程信号或时钟中断唤醒,进入运行队列。
不可中断睡眠状态(深度睡眠状态)(TASK_UNINTERRUPTIBLE):其和浅度睡眠基本类似(也在阻塞),但有一点就是不可被其他进程信号或时钟中断唤醒。
暂停状态(TASK_STOPPED):进程暂停执行接受某种处理(进程被挂起,不是阻塞态)。 向进程发送一个SIGSTOP信号(Ctrl+Z),它就会因响应该信号而进入暂停状态
跟踪状态(TASK_TRACED):一个正在调试的进程就是跟踪状态。
僵尸状态(TASK_ZOMBIE):一个进程已经结束但未释放PCB。这是一种不正常的进程状态,编程中应避免这样的情况。
如果了解父子进程的概念,就知道如果一个子进程在父进程结束之前先退出,父进程会忽略子进程发给父进程的退出信号,从而无法让子进程的PCB释放。
僵尸进程甚至无法通过kill -9强杀命令杀死
,具体细节见下一篇博客~
死亡状态(TASK_DEAD):一个进程即将退出,PCB随之也会销毁。所以死亡状态是非常短暂的,几乎不可能通过ps命令捕捉到(仅作概念了解)。
一个普通的死循环进程mytest
,通过指令ps aux | grep mytest
可以看到该进程为R运行状态;
R+
表示在前台执行的进程,任何进程状态后跟 + 表示在前台,- 表示在后台。
通过指令kill -[进程号]
或Ctrl + C(必须在当前执行窗口)
即可退出运行态或睡眠态的进程;
运行或睡眠的进程通过指令kill -STOP [PID]
或Ctrl + Z(必须在当前执行窗口)
即可将此在前台执行的进程放到后台,挂起暂停(T暂停状态);
如何唤醒正在挂起的进程?
通过指令fg [jobID]
可将进程放到前台并唤醒;
通过指令bg [jobID](或kill -CONT [pid])
可将进程放到后台并唤醒;
kill -[进程号]
或Ctrl + C
对于挂起进程无效!挂起进程只能通过进程强杀指令kill -9 [pid]
退出;
kill -[进程号]
或Ctrl + C
对于僵尸进程无效 !通过进程强杀指令kill -9 [pid]
也无效。