UNIX 进程揭秘( 三 )


清单 5. 同时对同一文件执行读取和写入的两个进程
#include
#include
#include
#include
#include
#include
int main(void) {
int fd_in, fd_out;
char buf[1024];
memset(buf, 0, 1024); /* clear buffer*/
fd_in = open("/tmp/infile", O_RDONLY);
fd_out = open("/tmp/outfile", O_WRONLY|O_CREAT);
fork(); /* It doesn't matter about child vs parent */
while (read(fd_in, buf, 2) > 0) { /* Loop through the infile */
printf("%d: %s", getpid(), buf);
/* Write a line */
sprintf(buf, "%d Hello, world!nr", getpid());
write(fd_out, buf, strlen(buf));
sleep(1);
memset(buf, 0, 1024); /* clear buffer*/
}
sleep(10);
}
sunbox$ gcc fdtest1.c -o fdtest1
sunbox$ ./fdtest1
2875: 1
2874: 2
2875: 3
2874: 4
2875: 5
2874: 6
2874: 7
sunbox$ cat /tmp/outfile
2875 Hello, world!
2874 Hello, world!
2875 Hello, world!
2874 Hello, world!
2875 Hello, world!
2874 Hello, world!
2874 Hello, world!
清单 5 是用于打开文件的简单程序,并派生 (fork) 为父进程和子进程 。每个进程从同一文件描述符(它只是一个包含数字 1 至 7 的文本文件)执行读取操作,并连同 PID 一起打印所读取的内容 。在读取一行之后,将 PID 写到输出文件 。当输入文件中没有其他字符可供读取时,循环结束 。
清单 5 的输出表明,当一个进程从该文件读取时,两个进程的文件指针都在移动 。同样地,当向某个文件写入时,下一个字符被写到文件结尾 。这是非常有意义的,因为内核跟踪打开文件的信息 。文件描述符只不过是进程的标识符 。
您可能还知道,标准输出(屏幕)也是一个文件描述符 。此文件描述符在 fork 调用期间被复制,这就是两个进程都能对屏幕执行写入操作的原因 。
父进程或子进程的终止
进程必须在某个时候终止 。问题只是哪个进程首先终止:父进程还是子进程 。
父进程在子进程之前终止
如果父进程在子进程之前终止,孤立的子进程需要知道它们的父进程是谁 。记住,每个进程都有父进程,并且您可以跟踪从每个子进程一直到 PID 1(或称为 init)的整个进程家族树 。当某个父进程终止时,init 将接纳所有子进程,如清单 6 所示 。
清单 6. 在子进程之前终止的父进程
#include
#include
int main(void) {
int i;
if (fork()) {
/* Parent */
sleep(2);
_exit(0);
}
for (i=0; i < 5; i) {
printf("My parent is %dn", getppid());
sleep(1);
}
}
sunbox$ gcc dIE1.c -o die1
sunbox$ ./die1
My parent is 2920
My parent is 2920
sunbox$ My parent is 1
My parent is 1
My parent is 1
在此例中,父进程调用 fork,等待两秒钟,然后退出 。子进程在五秒钟内继续打印其父 PID 。可以看到,PPID 在父进程终止后更改为 1 。Shell 提示符的返回也是非常有趣的 。由于子进程在后台运行,父进程一终止,控制即返回到 Shell 。
子进程在父进程之前终止
清单 7 与清单 6 相反——即在父进程之前终止的子进程 。为更好地说明所发生的事情,进程本身中没有打印任何内容 。而有趣的信息来自于进程清单 。
清单 7. 子进程在父进程之前终止
sunbox$ cat dIE2.c
#include
#include
int main(void) {
int i;
if (!fork()) {
/* Child exits immediately*/
_exit(0);
}
/* Parent waits around for a minute */
sleep(60);
}
sunbox$ gcc die2.c -o die2
sunbox$ ./die2 &
[1] 2934
sunbox$ ps -ef | grep 2934

推荐阅读