1、程序foo.c的源代码如下:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int i = 0;
printf("PID=%d\n", getpid());
for (;;) {
if (!fork())
return 0;
sleep(1);
printf("%d\n", ++i);
}
}
编译链接后生成的可执行程序为foo,运行./foo得到的第一行输出为:
PID=7812
然后程序继续运行,一段时间以后,在其他终端上执行vi bar.c失败,得到的提示信息为:
-bash: fork: retry: Resource temporarily unavailable
A、Linux之间多个进程的虚拟地址空间是独立的、隔离的,出现这样的异常现象与foo的运行无关
B、在另外一个终端上执行killall foo之后,系统恢复正常
C、在执行foo程序的终端上按下Ctrl-C导致foo程序终止后,系统恢复正常
D、在另外一个终端上执行reboot,系统重启后一切正常
A、程序中第9行if (!fork())应该修改为if (fork() == 0)。尽管语义相同,但可读性不好,前者容易误导别人是判断fork失败,fork失败将不创建子进程,实际上是fork成功且自身是子进程。
fork()后子进程直接终止,就是产生了僵尸,但是父进程没有执行wait消除僵尸。kill是内部命令,不需要创建新的进程,Ctrl-C也不需要创建进程,所以可以把foo进程杀死,foo的所有子进程(尽管都是僵尸状态),不会成为foo的父进程的子进程,而是成为操作系统进程1的子进程,1号进程会删除僵尸子进程,系统恢复正常,可以创建新的进程。reboot和killall都是外部命令,需要启动新的进程,当僵尸进程把操作系统内核中的全部进程槽占满了之后,启动失败。
如果foo进程是一个网络服务后台进程,脱离终端在后台运行,出现这样的问题,任何用户也不可能再完成登录,因为登录就需要创建shell进程,就算知道了PID连执行kill命令的机会都没有。执行关机命令的机会都没有,就麻烦了。
如果foo进程是后台进程没有机会Ctrl-C,即使有一个已登录的终端,若不知道进程的PID号,ps运行不了,也没法完成kill
2、在你自己的Linux系统上编个程序测试一下,你的系统最多可创建的进程数在以下哪个区间?
A、2000以上
B、200-499
C、500-999
D、1000-2000
这个题目是个动手题目,代码如何写?
仿照第一题写一个C代码就好
核心就是确保所有的子线程都是同一个父线程创建的,就容易统计了。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
int num=0;
while(1){
if(fork()==0)
{
printf("create %d child\n",num);
return 0;
}
else{
num++;
}
}
return 0;
}
3、程序foo.c在修改数据文件foo.dat时,采取这样的方式:调用两次open分别返回了文件描述符fd1和fd2,下面那个描述是正确的:
A、fd1和fd2虽然打开的是同一个文件,访问fd1和fd2使用的却是不同当前读写位置指针
B、fd1和fd2既然打开的是同一个文件,访问fd1和fd2使用的是同一个当前读写位置指针
C、fd1是已经打开foo.dat的文件描述符,再次打开foo.dat时,打开失败,根本得不到有效的fd2
D、fd1和fd2既然打开的是同一个文件,重复打开一个文件,fd1与fd2必然相等,这种做法没有意义
4、如果fork后父子进程都不执行exec系统调用,那么,父子进程将执行完全相同的程序,只是可能运行程序的不同分支。如果父子进程将fork的返回值都忽略,那么父子进程执行的程序分支也必然相同。
x
前半句是正确的,但后半句就不对了。至少同样的程序父子getpid()得到的值就不一样,而且,处理数据时,比如:获取当前时间坐标gettimeofday()等与环境相关的函数,父子进程也会得到不同的值,因此,父子进程执行的程序分支依然可能会不同。
5、在xsh1.c程序中,重定向功能是由父进程完成的,设置好重定向之后,才引导运行子进程的程序。
x
xsh1.c
查看程序可以知道,父线程做的事情是对输入的命令行参数进行切割,子进程再执行分割好的指令
重定向是fork后子进程干的
6、执行输入重定向的代码如下(未考虑差错处理)
fd0 = open(filename, O_RDONLY);
dup2(fd0, 0);
close(fd0);
其中,最后一个close不调用的话,对系统运行的正确性没有影响。
√
int dup2(fd1, fd2)
复制文件描述符fd1到fd2
fd2可以是空闲的描述符
如果fd2是已打开的文件,则关闭已打开的文件
Linux一切皆文件,每运行一个进程,会默认分配0、1、2文件描述符分别为标准输入,标准输出,标准错误,打开的文件,如果不手动关闭close的话,影响不大,进程结束后会自动关闭。每个进程的文件描述符数量是有限的,不适用的时候手动关闭是一个好的习惯
7、某个程序foo持续不间断运行,运行时,间歇性在标准输出设备输出文本信息。可以编写一个程序加载foo运行并创建一种输出重定向机制,不用修改foo的程序,就能做到每天的输出信息重定向到不同的文件中。
×
8、下列程序在终端上一共打印出多少行?
int main()
{
int i;
for (i = 0; i < 4; i++) {
printf("i = %d\n", i);
fork();
}
}
15
fork()生成的子进程,和主线程的当前信息一切皆相同,很容易算出是1+2+4+8=15,可以自行写个代码运行一下看看。