深入理解计算机系统(第二版) 家庭作业 第八章


8.9
进程对
是否并发
AB
No
AC
Yes
AD
Yes
BC
Yes
BC Yes
CD Yes

8.10
A. 调用一次,返回两次: fork
B. 调用一次,从不返回: execve, longjmp
C. 调用一次,返回一次或者多次: setjmp

8.11
4行

8.12
8行

8.13
->x=2
->x=4->x=3
满足这种拓扑即可。

8.14
主进程只打印一行。
主进程的直接子进程会打印一行,子进程的子进程又打印一行。
所以是3行。

8.15
这里的子进程不是exit,而是return,说明两个子进程都要到回到main函数去打印那里的hello。所以是5行。

8.16
输出counter = 2,因为全局变量也是复制的,而不是共享的。

8.17
满足
Hello--->1->Bye
      \        \    
       \--->0---->2-->Bye
这种拓扑即可。
Hello
1
Bye
0
2
Bye
Hello
1
0
Bye
2
Bye
Hello
0
1
Bye
2
Bye

8.18
画一下进程图就可以知道。
深入理解计算机系统(第二版) 家庭作业 第八章_第1张图片
所以ACE是可能的。

8.19
总共会输出2^n行。

8.20
其实这道题不需要你在环境变量里抓取name,只要用execve。
int main(int argc, char* args[])
{
    execve("/bin/ls", args, environ); //没有错误处理,注意环境变量
    return 0;
}

8.21
abc或者bac。c肯定在a和b之后。

8.22
不太清楚/bin/sh -c command中,-c以及command的意义。
所以把-c和command都当做/bin/sh的参数吧。
但是如果command有空格怎么办?
int mysystem(char *command)
{
    int status;
    char *argv[4];
    char *a0 = "sh";
    char *a1 = "-c";
    iffork()==0 ) /*子进程*/
    { 
        argv[0] = a0;
        argv[1] = a1;
        argv[2] = command;
        argv[3] = NULL;
        execve("/bin/sh", args, environ);
        return -1//执行异常
    }
    else/*父进程*/
        ifwait(&status) > 0)
        {
            if(WIFEXITED(status) != 0)
                return WEXITSTATUS(status);
            else return status;
        }
        else return -1//wait异常
    }
}

8.23
一个可能的原因是,在第一个信号发给父进程之后,父进程进入handler,并且阻塞了SIGUSR2,第二个信号依然可以发送,然而,之后的3个信号便会被抛弃了。因为是连续发送,所以很可能是没等上下文切换,这5个信号就同时发送了。所以只有2个信号被接收。

8.24
#include "csapp.h"
#define N 2

int main()
{
    int status, i;
    pid_t pid;
    char errorInfo[128];
    /* Parent creates N children */
    for(i=0;i         if ((pid = Fork()) == 0/* Child */
            exit(100+i);

    /* Parent reaps N children in no particular order */
    while ((pid = waitpid(-1, &status, 0)) > 0) {
        if (WIFEXITED(status))
            printf("child %d terminated normally with exit status=%d\n",
                    pid, WEXITSTATUS(status));
        else if(WIFSIGNALED(status))
        {
            //为什么只在写只读文本时才报错?下面的程序对所有异常退出都会提示
            printf("child %d terminated by signal %d: "
                pid, WTERMSIG(status) );
            psignal(WTERMSIG(status), errorInfo); //psignal会打印sig的信息
        }
    }
    /* The only normal termination is if there are no more children */
    if (errno != ECHILD)
        unix_error("waitpid error");
    exit(0);
}

8.25
fgets的定义如下:
char *fgets(char *buf, int bufsize, FILE *stream);
参数:
*buf: 字符型指针,指向用来存储所得数据的地址。
bufsize: 整型数据,指明buf指向的字符数组的大小。
*stream: 文件结构体指针,将要读取的文件流。

这个应该是用alarm发送信号给自己,然后在信号处理程序里面做文章。
显然,在tfgets里一开始需要调用fgets。然而,因为五秒时间到了,fgets还没有返回,所以我们必须在处理程序里直接跳转到某个地方进行tfgets的NULL返回。这就需要用到非本地跳转。

#include
#include
#include
#include
#include
#include
#include
sigjmp_buf env;
void tfgets_handler(int sig)
{
    signal(SIGALRM, SIG_DFL);
    siglongjmp(env, 1);
}

char *tfgets(char *buf, int bufsize, FILE *stream)
{
    static const int TimeLimitSecs = 5;
    signal(SIGALRM, tfgets_handler)
    alarm(TimeLimitSecs);
    int rc = sigsetjmp(env, 1);
    if(rc == 0return fgets(buf, bufsize, stream);
    else return NULL; //alarm,time out
}
注意这里如果用非sig版本,程序将不会正确运行。(尝试了只会time out一次)。
sig版本是可以供信号处理程序使用的版本。

8.26
暂时没有做。感觉加上JID的话,得自己写程序来管理每个job。
1)需要定义一个struct结构体数组,JID是1,那么就是数组的第一个。
结构体中有pid和状态。状态分空,运行,停止等等。
难点是JID和pid的互相查找,有点像hash。
如果不用hash,就是枚举数组寻找pid。所以,结构体数组大小要先设定(最多运行的jobs数目),不能太大,否则会增加复杂度。
2)可以写一个addjob和deletejob函数,以pid为参数。
当然,对于后台运行的进程,要注意竞争。
3)需要写handler函数,当子进程运行完毕或终止,需要用handler函数来回收。
还需要写一些handler来实现发送消息的功能,比如ctrl-z和ctrl-c。
4)jobs就是列出数组中状态不为空的进程。
可以写一个searchJID(pid_t pid)函数,根据某个pid来查询JID,当然,这个是可以优化的,当前可以只写枚举。
5)fg和bg倒是比较简单,给子进程发送那些消息,让那些消息重新execve。这个好像也可以用非本地跳转来实现。




你可能感兴趣的:(深入理解计算机系统(第二版) 家庭作业 第八章)