《UNIX环境高级编程(第三版)》第8章习题

8.1 在图8-3程序中,如果用exit调用代替_exit调用,那么可能会使标准输出关闭,使printf返回-1。修改该程序以验证在你所使用的系统上是否会产生这种结果。如果并非如此,你怎样处理才能得到类似结果呢?

为了仿真子进程终止时关闭标准输出的欣慰,在调用exit之前加下列代码行:

为了观察其效果,用下面几行替代程序中的printf的语句。

还需要定义变量i和buf。

这里假设子进程调用exit时会关闭标注I/O流,但不关闭文件描述符STDOUT_FILENO。有些版本的标准I/O库会关闭与标准输出相关联的文件描述符从而引起write标准输出失败。在这种情况下,调用dup将标准输出复制到另一个描述符,write则使用新复制的文件描述符。

根据书后答案,修改图8-3程序,exercise0801.c如下

 

8.2 回忆图7-6中典型的存储空间布局,由于对应于每个函数调用的栈帧通常存储在栈中,并且由于调用vfork后,子进程运行在父进程的地址空间中,如果不是在main函数中而是在另一个函数中调用vfork,此后子进程又从该函数返回,将会发生什么?请编写一段测试程序对次进行验证,并且画图说明发生了什么。

exercise0802.c:

当函数调用vfork时,父进程的栈指针指向f1函数的栈帧。vfork使得子进程先执行然后从f1返回,接着子进程调用f2,并且f2的栈帧覆盖了f1的栈帧,在f2中子进程将自动变量buf的值置为0,即将栈中的1000个字节的值都置为0。从f2返回后子进程调用_exit,这时栈中main栈帧以下的内容已经被f2修改了。然后父进程从vfork调用后恢复继续,并从f1返回。返回信息虽然保存在栈中,但多半可能已经被子进程修改了。对于这个例子,父进程回复继续执行的结果要依赖于你所使用的UNIX系统的实现特征(如返回信息保存在栈帧中的具体位置、修改动态变量时覆盖了那些信息等)。通常的结果是返回一个core文件,但在你的系统中,产生的结果可能不同。

 

8.3 重写图8-6中的程序,把wait换成waitpid,不调用pr_exit,而从siginfo结构中确定等价的信息。

exercise0803.c

 

8.4 当用 $ ./a.out 执行 图8-13 中的程序一次时,其输出是正确的。但是若从该进程按下列方式执行多次,则其输出不正确。

原因是什么?怎样才能更正此类错误?如果使子进程首先输出,还会发生此问题吗?

在图8-13中,我们先让父进程输出,但是当父进程输出完毕子进程要输出时,要让父进程终止。是父进程先终止还是子进程先执行输出,要依赖于内核对两个进程的调度(另一个竞争条件)。在父进程终止后,shell会开始执行下一个程序,它也许会干扰子进程的输出。为了避免这种情况,要在子进程完成输出后才终止父进程。修改后的代码exercise0804.c

 

8.5 在图8-20 所示的程序中,调用execl,指定pathname为解释器文件。如果将其修改为调用execlp,指定testinterp的filename,并且如果目录/home/sar/bin 是路径前缀,则运行该程序时,argv[2]的打印输出是什么?

代码修改为exercise0805.c

 

对argv[2]打印的是相同的值(/home/bumzy/bin/testinterp)。原因是execlp在结束时调用了execve,并且与直接调用execl的路径名相同,会议图8-15。

 

8.6 编写一段程序创建一个僵死进程,然后调用system执行ps(1)命令以验证该进程是僵死进程。

exercise0806.c

执行程序结果如下(ps中z表示僵死进程)

8.7 8.10节中提及POSIX.1要求在exec时关闭打开目录流。按下列方法对此验证:对根目录调用opendir,查看在你系统上实现的DIR结构,然后打印执行时关闭标志。接着打开同一目录读并打印执行时关闭标志。

验证流程:

  1. opendir获取DIR结构指针。
  2. 用dirfd获取该打开目录的文件描述符。
  3. 用fcntl设置 F_GETFD 获取当前文件描述符标志。
  4. fd传入一个缓冲区中,供子进程使用。
  5. fork一个子进程,子进程exec另一个名为exercise0807_child的程序
  6. exercise0807_child验证fd是否被关闭。

exercise0807.c

exercise0807_child.c

 

One thought on “《UNIX环境高级编程(第三版)》第8章习题

发表评论

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