1、进程标识
进程ID 0的进程叫做调度进程,又叫做swapper(交换进程)。该进程不执行磁盘中的任何程序,因此也叫做系统进程。
进程ID 1的进程叫做init进程。该进程负责在内核自举后启动一个unix系统。它通常读系统的初始化文件(etc/rc*文件)。该进程绝不会终止。它是一个普通用户进程。需超级用户特权才能运行,并且是所有孤儿进程的父进程。
和进程有关的其它标示:进程ID,父进程ID,进程的实际用ID,进程的有效用户ID,进程的实际组ID,进程的有效组ID。
2、fork函数
一个现存进程调用fork函数是内核创建一个新进程的唯一方法(除了ID为0、1和2的进程)。
子进程和父进程继续执行fork之后的指令。子进程是父进程的复制品,他们并不共享存储空间部分。如果正文段是只读的,则父子进程共享正文段。
fork后,父子进程共享一个文件表项。
通过一个简单的例子说明:fork后,子进程和父进程都分别继续执行后续的代码,但子进程和父进程的执行先后并不确定,直至两个进程都分别执行完后续代码,才最后执行return语句退出程序。
当重新定向父进程的标准输出时,子进程的标准输出也被重新定向,fork的一个特性是所有的父进程的打开描述符都被复制到了子进程,父子进程相同的打开描述符共享一个文件表项。
父子进程共享同一文件位移量。
如果父子进程写到同一描述符文件,但又没有任何形式的同步方式,那么他们的输出就会相互混合。
fork之后对文件描述符的处理有下列两种情况:一种是父进程等待子进程完成。这种情况下,父进程不需对文件描述符进行任何的处理,当子进程终止后,它所进行读写操作的描述的文件位移量都做了相应的修改;另一种是父子进程各自执行不同的程序段。这种情况,fork之后,父子进程各自关闭它们不需使用的描述符,并且不干扰对方使用的文件描述符。在网络服务进程中是经常使用的。
fork的两种使用情况:
(1)父进程希望复制自己,使父子进程执行不同的程序段。例子:父进程等待委托者的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求。
(2)一个进程要执行一个不同的程序。这对shell是常见的情况,这种情况下,子进程从fork返回后立即调用exec。
3、vfork函数
它与fork函数的调用序列和返回值相同。但两者的语义不同。在这里仅作简单的介绍:
vfork用于创建一个新进程,而新进程的目的是exec一个新程序。但它并不将父进程的地址空间完全复制到子进程中,在子进程调用exec或exit之前,它在父进程的地址空间中运行。
vfork保证子进程先运行。
4、exit函数
进程有3种正常终止法和两种异常终止法。
不管进程如何终止,都会调用同一段内核代码,实现关闭进程打开的描述符并且释放占用的存储器等等。
并且我们希望终止进程通知父进程它是如何终止的。
僵尸进程:一个已经终止,但其父进程尚未对其作出处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程称为僵尸进程(zombie)。
5、wait和waitpid函数
获取进程的终止状态信息。
wait一直阻塞到一个进程终止前。如果调用者阻塞而且有多个子进程,则其中一个子进程终止时,wait就立即返回。如果等待一个指定的进程终止,该怎么做呢?
waitpid函数提供了wait函数没能提供的3个功能:
(1)等待一个特定的进程
(2)提供wait的非阻塞版本
(3)waitpid支持作业控制
6、竞态条件
概念:
如果一个进程希望等待一个子进程终止,则它必须调用wait函数。如果一个子进程要等待它的父进程终止,则可使用下列形式的循环:
while(getpid()!=1)
sleep(1);
这种方法的问题是浪费CPU,因为没隔1秒就唤醒一次调用者,进行条件测试。
在父、子进程的关系中,常常出现下述情况。在f o r k之后,父、子进程都有一些事情要做。例如,父进程可能以子进程I D更新日志文件中的一个记录,而子进程则可能要为父进程创建一个文件。
7、前面提出当fork创建子进程之后,子进程往往需要调用一种exec函数执行另一个函数,当进程调用一种exec函数时,该进程完全由新函数替代。而新程序从main处开始执行。调用exec并不创建新进程,所以前后的进程ID不便,exec只是由另一个程序替换了当前进程的正文、数据、堆和栈。
fork可以创建新进程,exec可以执行新程序;exit可以处理终止,wait可以等待终止。这些都是基本的进程控制原语。
8、解释器文件(?)
这种文件是文本文件,其起始行的形式是:
#! pathname【optional-argument】
在惊叹号和pathname之间的空格是任选的,例如下列常见的例子:#! /bin/sh
对这种文件的识别通常是内核作为exec系统调用处理的一部分来完成的。内核调用exec函数的进程实际执行的文件并不是该解释器文件,而是该解释器文件的第一行pathname所指定的文件。解释器文件与解释器的区分
9、system函数
在程序中执行一个命令字符串很方便,但利用systm喊数更方便。但其较依赖于操作系统。
因为system在其实现中调用了fork、exec和waitpid,因此有三种返回值。
例子:system(“date”);
10、进程时间
进程时间包扩:墙上时钟时间、用户cpu时间和系统cpu时间。任意进程都可通过调用times函数获得它自己及终止子进程的上述值。
用返回值相对值,可得到墙上时钟时间。