深入理解電腦系統_3e 第八章家庭作業 CS:APP3e chapter 8 homework

來源:互聯網
上載者:User

標籤:abort   i++   range   並行   --   ==   usr   lock   警示   


8.9

關於並行的定義我之前寫過一篇文章,參考:

並發與並行的區別 The differences between Concurrency and Parallel

+----------------------------+| Process pair    Concurrent?|+----------------------------+|  AB                 N      ||                            ||  AC                 Y      ||                            ||  AD                 Y      ||                            ||  BC                 Y      ||                            ||  BD                 Y      ||                            ||  CD                 Y      |+----------------------------+


8.10

A.

fork

B.

execve longjmp

C.

setjmp


8.11

4次

                      +-------------->   printf("hello\n")                      |                      | Fork                      | i = 1         +------------+-------------->   printf("hello\n")         |         |         |            +-------------->   printf("hello\n")         |            |         |            |         |            |+--------+------------+-------------->   printf("hello\n")       Fork          Fork       i = 0         i = 1


8.12

8次

                                                  main                   +-------> printf("hello\n")+--------> printf("hello\n")                   |                              main             +-----+-------> printf("hello\n")+--------> printf("hello\n")             |     Fork         Fork|     Fork                           main     +-------------+-------> printf("hello\n")+--------> printf("hello\n")     |             |                              main+----+             +-------> printf("hello\n")+--------> printf("hello\n")    doit()


8.13

保證x=4在x=3之前即可(拓撲排序),有三種情況:

A.

x=2 x=4 x=3

B.

x=4 x=2 x=3

C.

x=4 x=3 x=2

                           "x=4"                         "x=3"          +-------> printf("%d\n", ++x) +---> printf("%d\n", --x) +-->          |          |          |+---------+-------> printf("%d\n", --x) +----------------------------> x = 3   Fork                           "x=2"


8.14

3次

                   +-------> printf("hello\n") +--->                   |             +-----+-------> printf("hello\n") +--->             |     Fork         Fork|                                 main     +-------------------------------------------------> printf("hello\n")     |+----+    doit()


8.15

5次

                                                 main                   +-------> printf("hello\n")+--------> printf("hello\n")                   |                             main             +-----+-------> printf("hello\n")+--------> printf("hello\n")             |     Fork         Fork|                                   main     +-------------------------------------------------> printf("hello\n")     |+----+    doit()


8.16

counter = 1

          +--> counter-- +--+          |                 |counter=1 |                 v       +--+-------------->Wait(NULL)+--> printf("counter = %d\n", ++counter);           Fork


8.17

假設子進程正常退出;構成拓撲排序即可,有三種情況:

A.

Hello 1 Bye 0 2 Bye

B.

Hello 1 0 Bye 2 Bye

C.

Hello 0 1 Bye 2 bye


8.18

構成拓撲排序即可,ACE正確。

B中的第一個不可能是2。D中的第一個1後面不可能有兩個2。

                   +-->printf("0")+--->printf("2")                   |    +----->atexit+-+-->printf("1")+--->printf("2")    |              Fork    |              Fork+---+--------------+-->printf("1")   Fork            |                   +-->printf("0")


8.19

2^n

每次Fork都會使原來的進程數翻倍,最後每一個進程都會輸出一行,所以是2^n行。


8.20

書上說改變COLUMNS環境變數會使得ls改變輸出的寬度,但是在我的機器上即使用export改變該環境變數後,如果我再調用ls ,其依然按照終端的寬度輸出,而且COLUMNS被改變回原來的值,我懷疑是調用ls的時候系統重新探測終端寬度並設定了新的COLUMNS。

#include <unistd.h>#include <errno.h>#include <stdio.h>int main(int argc, const char *argv[], const char *envp[]){    if (execve("/bin/ls", argv, envp))    {      perror("Failed to execve /bin/ls:\n");    }    return 0;}

類型不一致可能會警示,這裡不會有問題。


8.21

滿足拓撲排序即可,兩種情況:

A.

abc

B.

bac

    +----->printf("a")+-------+    |                         |    |                         v+---+----->printf("b")+--->waitpid+--->printf("c")+-->   fork


8.22

根據man 3 system 的部分描述:

The  system()  library function uses fork(2) to create a child process that executes the shell command specified in command using execl(3) as follows:           execl("/bin/sh", "sh", "-c", command, (char *) 0);

我們可以得到execl調用後的進程關係圖:

根據man sh的部分描述:

EXIT STATUS     Errors that are detected by the shell, such as a syntax error, will cause     the shell to exit with a non-zero exit status.  If the shell is not an     interactive shell, the execution of the shell file will be aborted.  Oth‐     erwise the shell will return the exit status of the last command exe‐     cuted, or if the exit builtin is used with a numeric argument, it will     return the argument.

可以看到Otherwise the shell will return the exitstatus of the last command executed這句話,也就是說,command執行的狀態會稱為sh的返回狀態,所以我們回收sh並判斷其返回狀態即可。

#include <sys/wait.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>int mysystem(char *command){    pid_t sh_pid;    int sh_status;    if ((sh_pid = fork()) == 0)    {        execl("/bin/sh", "sh", "-c", command, (char *) 0);    }        else    {        if ((waitpid(sh_pid, &sh_status, 0)) == sh_pid)        {            if (WIFEXITED(sh_status))            {                return WEXITSTATUS(sh_status);            }            else if (WIFSIGNALED(sh_status))            {                fprintf(stderr, "command terminated by signal number %d.\n", WTERMSIG(sh_status));                if (WCOREDUMP(sh_status))                {                    fprintf(stderr, "core dumped...\n", );                }                return WTERMSIG(sh_status);            }            else            {                fprintf(stderr, "command terminated abnormally.\n");                fprintf(stderr, "return status information...\n");                return sh_status;            }        }        else        {            fprintf(stderr, "Failed to reap /bin/sh.\n");            return EXIT_FAILURE;        }    }}


8.23

一個典型的訊號不能累加的問題。

當子進程連續向父進程發送5個SIGUSR2訊號時,第一個訊號傳送過程如下,其中A代表子進程,C代表父進程:

當父進程C接到訊號後,它進入訊號處理函數,並暫時將這個訊號屏蔽(設定block位),這時子進程還在不斷的向父進程發送所有剩下的同類訊號,pending位被再次置1,而接下來的訊號則會被遺棄(只有一個pending位,沒辦法計數),當父進程C的訊號處理函數退出後,block位被置零,剛剛pending的訊號再次被送入父進程C,父進程再次進入訊號處理函數,這時子進程已經完成所有的訊號發送,所以父進程不會再次進入訊號處理函數了。綜上,父進程C只會進入兩次訊號處理函數,即counter只會被加2而非5。


8.24

書上說要使用庫函數psignal訊號的描述,man 3 psignal描述如下:

#include <signal.h>void psignal(int sig, const char *s);       The  psignal()  function  displays a message on stderr consisting of the string s, a colon, a space, a string describing the signal number sig, and a  trailing  newline. If  the  string  s  is  NULL  or  empty, the colon and space are omitted. If sig is invalid, the message displayed will indicate an unknown signal.

將Figure 8.18的代碼改為:

#include <stdio.h>#include <signal.h>#include <sys/wait.h>#include <sys/types.h>#include <errno.h>#include <unistd.h>#define N 2int main() {    int status;    pid_t pid;       for (int i = 0; i < N; i++)    {        if (((pid = fork()) == 0))        {            int *p = 0;            *p = 0; /* Segmentation fault (core dumped) */            return 0;        }    }                                                          while ((pid = wait(&status)) > 0)     {         if (WIFEXITED(status))        {            printf("child %d terminated normally with exit status=%d\n"                , pid, WEXITSTATUS(status));         }                                           else if (WIFSIGNALED(status))        {            fprintf(stderr, "child %d terminated by signal %d"                , pid, WTERMSIG(status));            psignal(WTERMSIG(status), " ");        }        else        {            fprintf(stderr, "child %d terminated abnormally with status information=%d\n"                , pid, status);        }    }    if (errno != ECHILD)    {        fprintf(stderr, "waitpid error");    }                            return 0;}

運行輸出:


8.25

倒計時可以用alarm實現,其到指定時間後會raise一個SIGALRM訊號, man 2 alarm部分描述:

#include <unistd.h>unsigned int alarm(unsigned int seconds);alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds.If seconds is zero, any pending alarm is canceled.In any event any previously set alarm() is canceled.

我們收到這個訊號後,就要想辦法終止等待中的讀入並返回NULL。其中一個辦法是使用setjmp.h ,我們在第一次使用setjmp(buf)時進入正常的讀入(此時setjmp傳回值為0),但當訊號出現(時間截止),訊號處理函數就會longjmp(buf,1) (此時setjmp傳回值為1),根據傳回值的不同,這時我們便進入return NULL語句。

#include <stdio.h>#include <signal.h>#include <unistd.h>#include <setjmp.h>#define TIMEOUT ((unsigned int)5)#define SIZEOFBUF 1024jmp_buf buf;void SIGALRM_handler(int signum){    longjmp(buf, 1);}char *tfgets(char *s, int size, FILE *stream){    if (signal(SIGALRM, SIGALRM_handler) == SIG_ERR)    {        perror("Failed to install SIGALRM_handler");        return NULL;    }    else    {        alarm(TIMEOUT); /* raise SIGALRM after TIMEOUT seconds */    }    if (!setjmp(buf))    {        return fgets(s, size, stream);    }    else    /* longjmp from SIGALRM_handler */    {        return NULL;    }}int main(int argc, char const *argv[]){    char temp_bufer[SIZEOFBUF];    char *result = tfgets(temp_bufer, SIZEOFBUF, stdin);        if (result)    {        printf("Input : %s\n", result);    }    else    {        fprintf(stderr, "Time out!\n");    }        return 0;}

運行輸出(第二次輸入逾時):


8.26

這個四星的題目實際上就是本章對應的ShellLab(tsh)實驗,我做了以後會把該實驗對應的writeup連結發上來。

深入理解電腦系統_3e 第八章家庭作業 CS:APP3e chapter 8 homework

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.