作業系統概念(Operating System Concepts Ninth Edition恐龍書)第三章課後非程式設計題答案

Sampson Clarence發表於2019-01-14

CHAPTER 3

In this chapter we introduce the concepts of a process and concurrent execution;
These concepts are at the very heart of modern operating systems. A process is a
program in execution and is the unit of work in a modern time-sharing system. Such
a system consists of a collection of processes: Operating-system processes executing
system code and user processes executing user code. All these processes can
potentially execute concurrently, with the CPU (or CPUs) multiplexed among them. By
switching the CPU between processes, theoperating system can make the computer more
productive. We also introduce the notion of a thread (lightweight process) and
interprocess communication (IPC). Threads are discussed in more detail in Chapter 4.
在本章中,我們將介紹程式和併發執行的概念;這些概念是現代作業系統的核心。一個程式就是正在執行中
的程式,並且程式是現代分時系統的工作單元。這樣的系統由一組程式組成: 作業系統程式執行使用者程式碼
並且使用者程式執行使用者程式碼。所有這些程式都可以潛在併發執行,在它們之間多路複用CPUs.通過CPU在進
程間切換,作業系統可以讓計算機更有生產力。我們也介紹了執行緒(輕量級執行緒概念)和程式間通訊(IPC).
執行緒將在第四章中詳細討論


Exercises

3.1 Describe the differences among short-term, medium-term, and long-term scheduling.
描述短期排程、中期排程和短期排程的差異
Answer:
a. Short-term (CPU scheduler)—selects from jobs in memory those jobs that are
ready to execute and allocates the CPU to them.
a. 短期呼叫(CPU呼叫程式)–從記憶體中的作業中選擇當前的將要準備執行的作業,並且分配CPU給
它們
b. Medium-term—used especially with time-sharing systems as an intermediate
scheduling level. A swapping scheme is implemented to remove partially run programs
from memory and reinstate them later to continue where they left off.
b. 中期呼叫特別在分時系統作為及時排程層使用。 實現一個交換方案來從記憶體中刪除部分執行程式,
隨後恢復他們,繼續接著執行
c. Long-term (job scheduler)—determines which jobs are brought into memory for
processing.
The primary difference is in the frequency of their execution. The
short-term must select a new process quite often. Long-term is used much less often
since it handles placing jobs in the system and may wait a while for a job to finish
before it admits another one.
c. 長期排程程式(作業排程程式)–確定將那些作業放入記憶體中處理。
主要的區別在於它們的執行頻率。短期呼叫必須經常選擇新的程式.長期排程程式被使用的更少,因為它處理
在系統中放置作業,並且可能要等待作業完成一段時間才繼續另一個


3.2 Describe the actions taken by a kernel to context-switch between processes.
核心採取一些動作以便在兩個程式之間進行上下文切換,請描述一下
Answer:
In general, the operating system must save the state of the currently running
process and restore the state of the process scheduled to be run next. Saving the
state of a process typically includes the values of all the CPU registers in
addition to memory allocation. Context switches must also perform many
architecture-specific operations, including flushing data and instruction caches.
通常,作業系統必須儲存當前正在執行的程式的狀態,並且恢復計劃下一步執行的程式的狀態。
儲存a程式的狀態通常包括CPU暫存器的值,以及牛才能分配。上下文交換必須也執行許多特定於結構的
操作,包括重新整理資料和指令快取


3.3 大家隨便畫畫,試試命令


3.4 Explain the role of the init process on UNIX and Linux systems in regards to
process termination.

針對Unix和Linux系統的init程式在程式終止方面的作用,請解釋一下
Answer:
When a process is terminated, it briefly moves to the zombie state and remains
in that state until the parent invokes a call to wait(). When this occurs, the
process id as well as entry in the process table are both released. However, if a
parent does not invoke wait(), the child process remains a zombie as long as the
parent remains alive. Once the parent process terminates, the init process becomes
the new parent of the zombie. Periodically, the init process calls wait() which
ultimately releases the pid and entry in the process table of the zombie process.
當程式終止時,它會短暫的移動到殭屍狀態,並保持該狀態(成為殭屍程式),直到父程式呼叫
wait()方法。當呼叫後,殭屍程式的id和程式表中的條目都將被釋放.


3.5 Including the initial parent process, how many processes are created by the
program shown in Figure 3.32?

包括初始的父程式,總共下面建立了多少個程式
Answer:
16 processes are created. The program online includes printf() statements to
better understand how many processes have been created.
建立了16個程式,該程式可以加入printf()語句來更好說明建立了幾個程式

#include <stdio.h>
#include <unistd.h>
int main() 
{
	int i;
	for(i = 0; i < 4; i++)
		fork();
	return 0;
}

將其修改成這樣,可以列印出15個不同pid,加上父程式,一共16個程式

#include <stdio.h>
#include <unistd.h>
int main() 
{
	int i;
	int pid = 0;
	for(i = 0; i < 4; i++)
	{
		pid = fork();
		printf("pid:%d\n", pid);
		printf("----\n");
	}
	return 0;
}

可以參考這個部落格
fork()面試題
迴圈中fork()程式數量


3.6 Explain the circumstances when the line of code marked printf(“LINE J”) in
Figure 3.33 is reached.

解釋如圖所示的標記為printf(“LINE J”)的行所能執行的環境,請解釋一下

#include<sys/types.h>
#include <unistd.h>
#include<stdio.h>

int main() 
{
    pid_t pid;
    /*fork a child process*/
    pid = fork();

    if(pid < 0)
    {/*error occurred*/
        fprintf(stderr, "Fork Failed");
        return 1;
    } 
    else if(pid == 0)
    {/*child process*/
        execlp("/bin/ls", "ls", NULL);
        print("LINE J");
    }
    else 
    {/* parent process*/
        /* parent will wait for the child to complete*/
        wait(NULL);
        printf("Child Complete");
    }

    return 0;
}

將程式適當更改:
可以看到下面的程式列印出來了父程式和子程式的pid,exec是列出當前目錄的所有檔案,
可以看到執行成功,因此不會返回控制

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int wait();
int main()
{
    pid_t pid;
    /*fork a child process*/
    pid = fork();
	/*
	注:
	對於標準輸出裝置stdout,輸出一般都有緩衝,當遇到重新整理標誌或緩衝滿時
	才把緩衝的資料輸出到標準輸出裝置中。printf()函式採用行緩衝式輸出,
	遇到\n或者緩衝區滿時,才會輸出。
	因此\n才能輸出,否則是沒有東西的。
	*/
    printf("%d\n", pid);
    if(pid < 0)
    {/*error occurred*/
        fprintf(stderr, "Fork Failed");
        return 1;
    }
    else if(pid == 0)
    {/*child process*/
	/*
	系統呼叫exec()載入二進位制檔案到記憶體(破壞了包含系統呼叫exec()的原來程式的記憶體內容)
	,並開始執行。由於呼叫exec()用新程式覆蓋了程式的地址空間,所以呼叫exec()除非出現
	錯誤,不會返回控制
	*/
        execlp("/bin/ls", "ls", NULL);
        printf("LINE J");
    }
    else
    {/* parent process*/
        /* parent will wait for the child to complete*/
        wait(NULL);
        printf("Child Complete");
    }

    return 0;
}

Output:

29360
0
createpro  createProcess3.5.c  executeEnv3.6.c  test  第三章課後理論題.md

Answer:
The call to exec() replaces the address space of the process with the program
specified as the parameter to exec(). If the call to exec() succeeds, the new
program is now running and control from the call to exec() never returns. In this
scenario, the line printf(“Line J”); would never be performed.However, if an error
occurs in the call to exec(), the function returns control and therefor the line
printf(“Line J”); would be performed.
exec函式作用是根據指定的檔名找到可執行檔案,並用它來取代呼叫程式的內容.如果exec()呼叫
成功,則新程式執行,並且永遠不會從exec()返回。這種情況下,printf("Line J);永遠不會被執行.
但是,如果exec()呼叫發生錯誤,函式返回-1,因此printf(“Line J”)將會被執行.


3.7 Using the program in Figure Figure 3.34, identify the values of pid at lines
A, B, C, and D. (Assume that the actual pids of the parent and child are 2600 and
2603, respectively.)

採用圖3.34程式,確定A、B、C、D中pid的值.(假定父程式和子程式的pid分別為2600和2603)

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid, pid1;

    /* fork a child process*/
    pid = fork();

    if(pid < 0)
    {/*error ocurred*/
        fprintf(stderr, "Fork Failed");
        return 1;
    }
    else if(pid == 0) 
    {/*child process*/
        pid1 = getpid();
        printf("child: pid = %d", pid); /*A*/
        printf("child: pid1 = %d", pid1);/*B*/
    }
    else 
    {/*parent process*/
        pid1 = getpid();
        printf("parent: pid = %d", pid);/*C*/
        printf("parent: pid1 = %d", pid1);/*D*/
        wait(NULL);
    }

    return 0;
}

Answer: A = 0, B = 2603, C = 2603, D = 2600
考的是fork()返回值,在父程式中,fork返回新建立子程式的程式id;
在子程式中,fork返回0;如果出現錯誤,fork返回一個負值


3.8 Give an example of a situation in which ordinary pipes are more suitable
than named pipes and an example of a situation in which named pipes are more
suitable than ordinary pipes.

對於普通管道和命名管道有時候可能一方更加合適,請舉例說明
Answer:
Simple communication works well with ordinary pipes. For example, assume
we have a process that counts characters in a file. An ordinary pipe can be
used where the producer writes the file to the pipe and the consumer reads the
files and counts the number of characters in the file. Next, for an example where
named pipes are more suitable, consider the situation where several processes may
write messages to a log. When processes wish to write a message to the log, they
write it to the named pipe. A server reads the messages from the named pipe and
writes them to the log file
簡單的通訊可以使用普通管道。例如,假設我們有一個計算檔案中字元數量的程式.可以使用
一個普通管道,生產者將檔案寫入管道,消費者從管道一段讀取檔案,並且計算檔案中的字元數。
接著,舉一個適合命名管道的例子。考慮多個程式可能會將訊息寫入日誌中的情景,當程式希望將
訊息寫入日誌,它們將其寫入命名管道。一個伺服器從命名管道中讀取訊息,並且將它們寫入到日誌
檔案


3.9 Consider the RPC mechanism. Describe the undesirable consequences that could
arise from not enforcing either the “at most once” or “exactly once” semantic.
Describe possible uses for a mechanism that has neither of these guarantees.

對於RPC機制,若沒有強制"最多一次"或"正好一次"的語義,描述一下所帶來的一些不必要的後果。
討論一下沒有這些強制保證的可能用途
Answer:
If an RPC mechanism cannot support either the “at most once” or “at least once”
semantics, then the RPC server cannot guarantee that a remote procedure will not
be invoked multiple occurrences. Consider if a remote procedure were withdrawing
money from a bank account on a system that did not support these semantics. It is
possible that a single invocation of the remote procedure might lead to multiple
withdrawals on the server.
如果RPC機制不支援"最多一次"或"至少一次"語義,RPC伺服器不能保證遠端過程不會被呼叫多次。
考慮一個遠端過程在一個不支援這種語義的系統上從一個銀行上取錢.遠端過程的一次呼叫將會導致
從伺服器上多次執行取錢操作
For a system to support either of these semantics generally requires the server
maintain some form of client state such as the timestamp described in the text.
If a system were unable to support either of these semantics, then such a system
could only safely provide remote procedures that do not alter data or provide
time-sensitive results. Using our bank account as an example, we certainly require
“at most once” or “at least once” semantics for performing a withdrawal (or deposit
!). However, an inquiry into an account balance or other account information such
as name, address, etc. does not require these semantics.
對於一個支援這兩種語義之一的系統通常需要伺服器維護客戶端的某種狀態。如文章中
為每個訊息附加時間戳。如果一個系統不能支援這兩種語義,那麼這樣一個系統只能安全地提供不需
交換資料或不需提供實時性的結果的遠端呼叫.以我們的銀行賬戶為例,我們對於取款會存款,肯定需
要這兩種語義之一。但是,查詢賬戶餘額或其他賬戶資訊,如姓名,地址,等等,不需要這些語義。


3.10 Using the program shown in Figure 3.35, explain what the output will be at
lines X and Y.

使用如圖3.35所示程式,解釋X、Y行輸出將會是什麼

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

#define SIZE 5

int nums[SIZE] = {0, 1, 2, 3, 4};

int main()
{
    int i;
    pid_t pid;

    pid = fork();
    if(pid == 0)
    {
        for(i = 0; i < SIZE; i++)
        {
            nums[i] *= -i;
            printf("CHILD: %d", nums[i]);/*LINE X*/
        }
    }
    else if(pid > 0)
    {
        wait(NULL);
        for(i = 0; i < SIZE; i++) 
            printf("PARENT: %d", nums[i]);/*LINE Y*/
    }
}

Answer:
注意,系統呼叫fork(),可建立新錦成,新程式的地址空間複製了原來程式的地址空間,注意是副本
Because the child is a copy of the parent, any changes the child makes will
occur in its copy of the data and won’t be reflected in the parent. As a result,
the values output by the child at line X are 0, -1, -4, -9, -16. The values output
by the parent at line Y are 0, 1, 2, 3, 4
由於child是parent的副本,任何發生在child中的改變將出現在它自己的資料拷貝上,並不會
影響parent父程式。因此,輸出結果是:
在子程式X行處, 0、-1、-4、-9、-16
在父程式Y行處, 0、1、2、3、4


3.11 What are the benefits and the disadvantages of each of the following?
Consider both the system level and the programmer level.

下面設計的優缺點是什麼?系統層次和使用者層次都要考慮
a. Synchronous and asynchronous communication
a. 同步和非同步通訊
b. Automatic and explicit buffering
b. 自動和顯示緩衝
c. Send by copy and send by reference
c. 複製傳送和引用傳送
d. Fixed-sized and variable-sized messages
d. 固定大小和可變大小訊息
Answer:
a. Synchronous and asynchronous communication—A benefit of synchronous
communication is that it allows a rendezvous between the sender and receiver.
A disadvantage of a blocking send is that a rendezvous may not be required and
the message could be delivered asynchronously. As a result, message-passing systems
often provide both forms of synchronization
同步和非同步通訊–同步的優點是它允許傳送方和接收方之間進行約定。阻塞傳送的一個缺點是可能
不能約定,並且訊息可能非同步傳遞.因此,訊息傳遞系統通常提供兩種形式的同步

b. Automatic and explicit buffering—Automatic buffering provides a queue 

with indefinite length, thus ensuring the sender will never have to block while
waiting to copy a message. There are no specifications on how automatic buffering
will be provided; one scheme may reserve sufficiently large memory where much of
the memory is wasted. Explicit buffering specifies how large the buffer is. In
this situation, the sender may be blocked while waiting for available space in the
queue.However, it is less likely that memory will be wasted with explicit buffering.
自動和顯示緩衝–自動緩衝提供一個具有不定長度的佇列,因此確保傳送方在等待複製訊息時永遠不必
阻塞.關於如何自動緩衝的規範沒有提供;一種方案可以保留足夠大的內容,這些記憶體被浪費了.顯示緩衝
指出了緩衝區的大小.在這種情況下,傳送方在等待佇列中可用的空間時被阻塞.但是,顯示緩衝不太可能
浪費記憶體.
c. Send by copy and send by reference—Send by copy does not allow the receiver
to alter the state of the parameter; send by reference does allow it. A benefit of
send by reference is that it allows the programmer to write a distributed version
of a centralized application. Java’s RMI provides both; however, passing a parameter
by reference requires declaring the parameter as a remote object as well.
複製傳送和引用傳送—複製傳送不允許傳送者去改變引數的狀態;通過引用傳送是可以的.引用傳送的
一個好處是它允許程式設計師編寫分散式版本的集中應用.Java的RMI都提供了.然而,通過引用傳送一個
引數還需要在將這個引數宣告為遠端物件
d. Fixed-sized and variable-sized messages—The implications of this are mostly
related to buffering issues; with fixed-size messages, a buffer with a specific size
can hold a known number of messages. The number of variable-sized messages that can
be held by such a buffer is unknown. Consider how Windows 2000 handles this situation:
with fixed-sized messages (anything < 256 bytes), the messages are copied from the
address space of the sender to the address space of the receiving process. Larger
messages (i.e. variable-sized messages) use shared memory to pass the message.
固定大小和可變大小訊息—這個的實現主要與緩衝問題有關;對於固定大小的訊息,具有特定大小的
緩衝區可以容納已經數量的訊息.可變大小訊息是不清楚的.考慮windows 2000處理如下情況:
對於固定大小的訊息(小於256位元組),從傳送方的地址空間複製到接受程式的地址空間。更大的訊息使用
共享記憶體傳遞訊息.(很明顯是提高效率,減少記憶體地址空間的浪費)


相關文章