系统编程之进程管理
一、引言 进程是操作系统中的重要概念,是对执行一定功能的程序的过程的抽象。这篇文章将简要说明进程的相关知识。介绍进程管理相关的函数,并通过这些函数实现重定向和进程间通信等功能。 二、进程简介 1. 程序执行原理 程序在编译后以二进制方式存在于外存上,执行的时候被操作系统载入内存。以 Linux 系统上的 C 语言编译出来的程序为例,载入的过程简单来说就是把编译完成的 ELF (Executable and Linkable Format 可执行与可链接格式) 文件的几个段的内容读取到内存指定位置,然后初始化寄存器的内容,将指令寄存器(比如cs:ip)指向程序入口,再初始化一些进程相关内容就完成了。 在某一次时钟中断发生的时候,进程主动陷入内核态,进行进程切换的系统调用,CPU 将切换到另一个进程工作。总而言之,整个计算机从开机到关机,就是一个不断创建、切换、终止进程的过程。 2. 进程概念的用途 早期的计算机一次只能执行一个程序,这种程序完全控制系统,并且访问所有系统资源。相比之下,现代计算机系统允许“同时”加载多个应用程序到内存,以便并发(轮流)执行。 这种改进要求对各种程序提供更严的控制和更好的划分。这些需求导致了进程概念的诞生。 进程是现代分时操作系统的工作单元,是操作系统向运行中的程序进行资源分配的单位。进程包括程序代码(文本),当前活动(程序计数器,寄存器的值),堆栈,数据端,堆。 需要注意区分程序和进程的概念。程序是被动实体,如存储在磁盘上的可执行文件;进程是活动实体,具有一个程序计数器用于表示下个执行命令和一组相关资源。 当一个可执行文件被加载到内存时,这个程序就成为进程。 两个进程可以与同一程序相关联,但当作两个单独的执行序列,虽然文本段相同,但是数据、堆、堆栈不同。 三. 进程管理 接下来介绍使用操作系统 API 进行进程管理的方法。 1. 使用 fork 创建新进程 #include <unistd.h> pid_t fork(); fork 无参数,返回一个用于指示子进程的 pid(对于子进程,返回值为 0)。其作用是创建一个子进程,共享父进程所有内容,并且这个子进程会接着 fork 下面的代码继续执行。fork有以下两种用法: 一个父进程希望复制自己,使父进程和子进程同时执行不同的代码段。 一个进程要执行一个不同的程序。在这种情况下,子进程从fork返回后立即调用exec。 如果在调用 fork 后子进程先于父进程结束,则子进程就会变为僵尸进程,虽然结束,却依然占据了进程表中的一个位置。为了避免这种情况,需要调用 wait 或 waitpid 来使父进程等待子进程结束,并释放子进程的信息。 #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid,int *status,int options); 下面将以一个程序作为例子。该程序由父进程创建两个子进程,父进程打印字符 B ,两个子进程分别打印 A 和 C ,并且要使最终的输出为 ABC 。...