每个进程都对应于一个运行中的程序。应用程序再运行时仿佛独自占用整个CPU,而不需要考虑何时需要把CPU让给其他应用程序:进程管理、CPU资源分配等任务交给操作系统。
新生状态 | new | 该状态表示—个进程刚刚被创建出来,还未完成初始化,不能被调度执行。在经过初始化过程之后,进程迁移至预备状态。 |
预备状态 | ready | 该状态表示进程可以被调度执行,但还未被调度器选择。由于CPU数量可能少于进程数量,在某一时刻只有部分进程能被调度到CPU上执行。此时,系统中其他的可被调度的进程都处于预备状态。在被调度器选择执行后’进程迁移至运行状态。 |
运行状态 | running | 该状态表示进程正在CPU上运行。当一个进程执行一段时间后,调度器可以选择中断它的执行并重新将其放回调度队列,它就迁移至预备状态。当进程运行结束,它会迁移至终止状态。如果一个进程需要等待某些外部事件,它可以放弃CPU并迁移至阻塞状态。 |
阻塞状态 | blocked | 该状态表示进程需要等待外部事件,暂时无法被调度。当进程等待的外部事件完成后,它会迁移至预备状态。 |
终止状态 | terminated | :该状态表示进程已经完成了执行,且不会再被调度。 |
进程具有独立的虚拟内存空间
进程控制块:
每个进程都通过一个数据结构来保存它的相关状态,如进程标识符(PID)、进程状态、虚拟内存状态、打开的文件等。
struct task_st{
volatile long state;
struct mm_struct *mm;
pid_t pid;
pid_t tgid;
...
}
进程上下文:
包括进程运行时的寄存器状态,其能够用于保存和恢复一个进程在处理器上运行的状态。当操作系统需要切换当前执行的进程时,就会使用上下文切换机制。
上下文切换:
该机制会将前一个进程的寄存器状态保存到PCB中,然后将下一个进程先前保存的状态写人寄存器,从而切换到该进程执行。
第一:创建进程的开销较大,需要完成创建独立的地址空间、载人数据和代码段、初始化堆等步骤。即使使用fork接口创建进程,也需要对父进程的状态进行大量拷贝。
第二:由于进程拥有独立的虚拟地址空间,在进程间进行数据共享和同步比较麻烦,一般只能基于共享虚拟内存页(粒度较粗)或者基于进程间通信(开销较高)。
操作系统的设计人员提出在迸程内部添加可独立执行的单元,它们共享进程的地址空间,但又各自保存运行时所需的状态(即上下文),这就是线程。
根据线程是由用户态应用还是由内核创建与管理’可将线程分为两类:用户态线程(user level thread)与内核态线程(kemel level thread)。
与内核态线程相比,用户态线程更加轻量级,创建开销更小,但功能也较为受限’,与内核态相关的操作(如系统调用)需要内核态线程协助才能完成。
多线程模型:为了实现用户态线程和内核态线程的协作。操作系统会建立两类线程之间的关系。
线程也有自己的线程控制块(Thread Control Block,TCB),用于保存与自身相关的信息。
线程本地存储(Thread Local Storage,TLS):一个名字,多份拷贝(与线程数量相同)的全局变量。