Linux开发环境及其应用 《第12周单元测验》及其解析

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,可以自行写个代码运行一下看看。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值