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,可以自行寫個代碼運行一下看看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章