APUE学习笔记-进程控制

前面一章学习了进程环境,本章我们将学习UNIX系统的进程控制,包括创建新进程、执行程序和进程终止。还将说明进程属性的各种ID——实际、有效和保存的用户ID和组ID……

1.进程标识

每个进程都有一个非负整型表示的唯一进程ID。

(1)系统中有一些专用进程,但具体细节随实现而不同。ID为0的进程通常是调度进程,常常被称为交换进程(swapper)。该进程是内核的一部分,它并不执行任何磁盘上的程序,因此也被称为系统进程。

(2)进程ID为1通常是init进程,在自举过程结束时由内核调用。此进程负责在自举内核后启动一个UNIX系统。init通常读取与系统有关的初始化文件,并将系统引导到一个状态。
(3)init进程绝不会终止。它是一个普通的用户进程,但是它以超级用户特权运行。

(4)除了进程ID,每个进程还有一些其他标识符。下列函数返回这些标识符:

注意:这些函数都没有出错返回。

2.函数fork

一个现有的进程可以调用fork函数创建一个新进程。

(1)由fork创建的新进程被称为子进程(child process)。fork函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新建子进程的进程ID。

(2)将子进程ID返回给父进程的理由是:一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。

(3)fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程可以通过调用getppid以获得其父进程的ID

(4)子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。

(5)fork函数示例:从中可以看到子进程对变量所做的改变并不影响父进程中该变量的值。

得出如下输出:

1)一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的,这取决于内核所使用的调度算法。

2)父进程和子进程共享同一文件偏移量,在fork之后处理文件描述符有以下两种常见的情况:

  • 父进程等待子进程完成。在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它曾进行过读、写操作的任一共享描述符的文件偏移量已做了相应更新。
  • 父进程和子进程各自执行不同的程序段。这种情况下,在fork之后,父进程和子进程各自关闭它们不需要使用的文件描述符,这样就不会干扰对方使用的文件描述符。

(6)父进程和子进程之间的区别如下:

  • fork的返回值不同
  • 进程ID不同
  • 这两个进程的父进程ID不同:子进程的父进程ID是创建它的进程的ID,而父进程的父进程ID则不变
  • 子进程的tms_utime, tms_stime, tms_cutime和tms_ustime的值设置为0
  • 子进程不继承父进程设置的文件锁
  • 子进程的未处理闹钟被清除
  • 子进程的未处理信号集设置为空集

(7)fork有以下两种用法

1)一个父进程希望赋值自己,使父进程和子进程同时执行不同的代码段。这在网络服务进程中最常见——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,是子进程处理此请求。父进程则继续等待下一个服务请求。

2)一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec。

3.函数exit

前一章所述,进程有5中正常终止及3种异常终止方式。

(1)不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。

(2)对任意一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于3个终止函数(exit, _exit, _Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数;在异常终止情况,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。

(3)内核为每个终止子进程保存了一定量的信息,所以当终止进程的父进程调用wait或waitpid时,可以得到这些信息。

(4)在UNIX术语中,一个已经终止,但是其父进程尚未对其进程善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程被称为僵尸进程(zombie)。ps(1)命令将将死进程的状态打印为Z。

4.函数wait和waitpid

(1)当一个进程正常或异常终止时内核就向其父进程发送SIGCHLD信号。父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用执行的函数(信号处理程序)。对于这种信号的系统默认动作是忽略它。

(2)调用wait或waitpid的进程可能会发生什么:

  • 如果所有子进程都还在运行,则阻塞。
  • 如果一个子进程终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
  • 如果它没有任何子进程,则立即出错返回。

(3)如果进程由于接收到SIGCHLD信号而调用wait,我们期望wait会立即返回。但是如果在随机时间点调用wait,则进程可能会阻塞。

这两个函数的参数statloc是一个整型指针。如果statloc不是一个空指针则终止进程的终止状态就存放在它所指的单元内。如果不关心终止状态,则可将该参数指定为空指针。

(4)这两个函数的区别如下:

  • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一选项,可使调用者不阻塞。
  • waitpid并不等待在其调用之后的第一个终止子进程,它有若干个选项,可控制它所等待的进程。

……

发表评论

电子邮件地址不会被公开。 必填项已用*标注