操作系统——进程

进程概念

进程不只是程序代码,程序代码有时称为文本段,进程还包括当前活动,通过程序计数器的值和处理器寄存器的内容来表示。进程包括 堆(是在进程运行是动态分配的内存)、栈(包括临时数据,如函数参数、返回值地址和局部变量表)和数据段(包括全局变量)

程序本身不是进程:程序只是被动实体,如存储在磁盘上包含一系列指令内容的文件(通常被称为可执行文件),而进程是活动实体,他有一个程序计数器用来表示下一个要执行的命令和相关资源集合。当一个可执行文件被装入内存中时,一个程序才能成为进程。

进程的状态

  • 新的: 进程正在被创建
  • 运行:指令正在被执行
  • 等待:进程等待某个事件的发生(如 I/O 完成或收到信号)
  • 就绪:进程等待分配处理器
  • 终止:进程完成任务

进程控制块

每个进程在操作系统内用进程控制块(process control block, PCB,也称为任务控制块)来表示。
PCB 中记录着进程的相关信息:

  • 进程状态
  • 程序计数器
  • CPU寄存器
  • CPU调度信息
  • 内存管理信息
  • 记账信息
  • I/O状态信息

进程调度

调度队列

进程进入系统时,会被加入到作业队列中,该队列包括系统中的所有进程。驻留在内存中就绪的、等待运行的进程保存在就绪队列中,该队列通常用链表来实现,其头节点指向链表的第一个和最后一个PCB 块的指针。每个PCB包括一个指向就绪队列的下一个PCB的指针域。

Linux 中的进程表示

Linux 系统中进程的控制块是通过C 结构task_struct来表示的。这个结构包含了表示一个进程和所需要的所有信息,包括进程的状态、调度和内存管理信息、打开文件列表和指向父进程和所有子进程的指针(创建进程的进程是父进程,被进程创建的进程为子进程)。stask_struct的这些字段包括:

1
2
3
4
5
pid_t pid; // 是一个整数值
long state;
unsigned int time_slice;
struct files_struct *files;
struct mm_struct *mm;

在Linux 内核中,所有活动的进程是通过一个名为 task_struct 的双向链表来表示的,内核为当前正在运行的进程保存了一个指针(current )

上下文切换

将CPU 切换到另一个进程需要保存当前进程的状态并恢复另一个进程的状态,这一任务称为上下文切换

进程操作

Linux 中 ps 命令可以得到一个进程列表。输入 ps -el 将会列出系统中所有当前活动进程的完整信息
当进程创建新进程时,有两种执行可能:

  1. 父进程与子进程并发执行
  2. 父进程等待,直到某个或全部子进程执行完。

新进程的地址空间也有两种可能:

  1. 子进程是父进程的复制品(具有与父进程相同的程序和数据)
  2. 子进程装入另一个新程序

在UNIX 系统中,每个进程都用一个唯一的整数形式的进程 标识符通过 fork() 系统调用,可创建新进程。新进程通过复制原来进程的地址空间而成立。这种机制允许父进程与子进程方便的进行通信。两个进程(父进程和子进程)都继续执行位于系统调用fork() 之后的指令。但是,有一点不同: 对于新(子)进程,系统调用 fork() 的返回值为 0, 而对于父进程,返回值为子进程的进程标识符(非零)。
通常,在系统调用 fork() 之后,一个进程会使用系统调用exec(), 以用来取代进程的内存空间。系统调用 exec()将二进制文件装入内存(消除了原来包含系统调用 exec()程序的内存映射),并开始执行。采用这种方式,两个进程能够相互通信,并能按各自的方法执行,父进程能创建更多的子进程,或者如果在子进程运行时没有什么可做,那么它采用系统调用 wait()把自己的移出就绪等待子进程的终止。

进程终止

当进程完成执行最后的语句并使用系统调用 exit()请求操作系统删除自身时,进程终止,这时,进程可以返回状态值(通常为整数)到父进程(通过系统调用wait())。所有进程资源(包括物理和虚拟内存,打开文件和I/O缓冲)会被操作系统释放

父进程终止子进程的原因有很多,如:

  • 子进程使用了超过它所分配到的一些资源(为判定是否发生这种情况,要求父进程有一个检查子进程状态的机制)
  • 分配给子进程的任务已经不再需要
  • 父进程退出,如果父进程终止,那么操作系统不允许子进程继续。

进程间通信

与其他进程共享数据的进那么该进程是协作的,一个进程不能影响其他进程或被其他进程所影响,那么该进程是独立的
进程间信息共享的原因:

  • 信息共享:由于多个用户可能对同样的信息感兴趣,所以必须提供环境以允许对这些信息进行并发访问。
  • 提高运算速度:如果希望一个特定任务快速执行,那么必须将它分成子任务,每个任务可以与其他子任务并行执行
  • 模块化:可能需要按模块化方式构造系统,可将系统功能分成独立进程或线程。
  • 方便:单个用户可以同时执行多个任务。

进程间通信的两种基本模式:

  • 共享内存
    在共享内存模式中,建立起一块供协作进程共享的内存区域,进程通过向此共享区域读或写入数据来交换信息。
  • 消息传递
    在消息传递模式中,通过在协作进程间交换消息来实现通信。

优缺点:

  • 共享内存
    优点: 速度快,只有在建立共享内存的时候才调用内核,其后不调用系统内核
    缺点:实现比消息传递难,有可能会产生冲突。

  • 消息传递
    优点: 比共享内存简单
    缺点: 消息传递通常使用系统调用来实现,因此需要更多的内核介入的时间消耗。

坚持原创技术分享,您的支持将鼓励我继续创作!