深入理解计算机系统 第8章 习题解析
这次更新第8章习题。
参考资料:
- https://blog.csdn.net/ustc_sse_shenzhang/article/details/105744435
- https://www.cnblogs.com/drfxiaoliuzi/p/5483317.html
- https://www.cnblogs.com/chan0311/p/9427356.html
- https://blog.csdn.net/weixin_47139649/article/details/113998453
- https://askubuntu.com/questions/484569/how-can-i-fix-setenv-command-not-found-error-ubuntu-12-04-4
- https://www.cnblogs.com/c-slmax/p/5244425.html
- https://stackoverflow.com/questions/3985193/what-is-bin-sh-c
- https://dreamanddead.github.io/CSAPP-3e-Solutions/chapter8/
csapp.h使用说明
将csapp.h复制到/usr/include:
sudo cp csapp.h /usr/include/
sudo cp csapp.c /usr/include/编译命令需要加上-lpthread:
gcc -o forkprob1 forkprob1.c -lpthread8.9
| 进程对 | 并发地? | 
|---|---|
| AB | 否 | 
| AC | 是 | 
| AD | 是 | 
| BC | 是 | 
| BD | 是 | 
| CD | 是 | 
8.10
- A. 调用一次,返回两次。- fork
 
- B. 调用一次,从不返回。- execve, longjmp
 
- C. 调用一次,返回一次或者多次。- setjmp
 
8.11
进程图:
- main, i = 0, Fork
	- child1, i = 1, Fork
		- child11, i = 2, hello
		- child1, i = 2, hello
	- main, i = 1, Fork
		- main, i = 2, hello
		- child2, i = 2, hello所以会输出4个hello输出行。
8.12
进程图:
- main, doit, Fork
	- child1, Fork
		- child1, printf, printf
		- child11, printf, printf
	- main, Fork
		- main, printf, printf
		- child2, printf, printf所以会输出8个hello输出行。
验证:
$ gcc -o forkprob4 forkprob4.c -lpthread
$ ./forkprob4
hello
hello
hello
hello
hello
hello
hello
hello8.13
子进程结果:
- 2
父进程结果:
- 4
- 3
父进程先结束:
4
3
2子进程先结束:
2
4
3或者:
4
2
38.14
进程图:
- main, doit, Fork
  - child1, return, printf, exit(0)
  - main, Fork
  	  - main, printf, exit(0)
  	  - child2, printf, exit(0)所以会输出3个hello输出行。
验证:
$ gcc -o forkprob5 forkprob5.c -lpthread
$ ./forkprob5
hello
hello
hello8.15
进程图:
- main, doit, Fork
  - child1, return, printf, exit(0)
  - main, Fork
  	  - main, printf, return, printf, exit(0)
  	  - child2, printf, return, printf, exit(0)所以会输出5个hello输出行。
验证:
$ gcc -o forkprob6 forkprob6.c -lpthread
$ ./forkprob6
hello
hello
hello
hello
hello8.16
子进程完成后退出,所以输出结果为:
counter = 2验证:
$ gcc -o forkprob7 forkprob7.c -lpthread
$ ./forkprob7
counter = 28.17
8.4在520页,只要给出满足条件的拓扑排序即可:
Hello, 1, Bye, 0, 1, Bye
Hello, 1, 0, Bye, 1, Bye
Hello, 0, 1, Bye, 1, Bye8.18
atexit参考资料:
atexit()最后调用。
进程图:
- main, Fork
	- child1, Fork
		- child11, printf("0"), printf("2")
		- child1, printf("1"), printf("2")
	- main, Fork
		- main, printf("1")
		- child2, printf("0")注意到1,0在2之前,所以A, C, E可能出现;
验证:
$ gcc -o forkprob2 forkprob2.c -lpthread
$ ./forkprob2
1120028.19
记行数为$a_n$,那么递推关系为
注意到
所以
8.20
参考资料:
- https://blog.csdn.net/weixin_47139649/article/details/113998453
- https://askubuntu.com/questions/484569/how-can-i-fix-setenv-command-not-found-error-ubuntu-12-04-4
csh中命令
setenv COLUMNS 40等价于bash中命令
export COLUMNS=40代码:
#include "csapp.h"
int main(int argc, char *argv[], char *env[]){
    printf("\n");
    printf("Environment variables:\n");
    for (int i=0; env[i] != NULL; i++){
        printf("    envp[%2d]: %s\n", i, env[i]);
    }
	
    execve("/bin/ls", argv, env);
    exit(0);
}编译运行:
$ gcc -o myls myls.c -lpthread
$ ./myls备注:默认的ls会重置COLUMNS,所以运行时不起作用。
8.21
参考资料:
- 父进程: - bc
 
- 子进程:- a
 
由于waitpid等待子进程结束,所以可能的输出结果为:
a b c
b a c8.22
参考资料:
代码:
mysystem.c
#include "csapp.h"
int mysystem(char *command){
    pid_t pid;
    if ((pid = Fork()) == 0){
        char *argv[4] = {"", "-c", command, NULL};
        if(execve("/bin/sh", argv, environ) < 0){
            return 0;
        }
    }
    /* Parent waits for foreground job to terminate */
    int status;
    if (waitpid(pid, &status, 0) > 0){
        // 正常终止
        if (WIFEXITED(status)){
            // 返回状态
            return WEXITSTATUS(status);
        }
        // 由未捕获的信号终止
        if (WIFSIGNALED(status)){
            // 返回信号编号
            return WTERMSIG(status);
        }
    }
    return status;
}
int main(int argc, char *argv[], char *env[]){
    int code = mysystem(argv[1]);
    printf("code is %d\n", code);
    exit(0);
}test.c:
#include "csapp.h"
int main(){
    printf("This is test program!\n");
    
    exit(4);
}测试:
$ gcc -o mysystem mysystem.c -lpthread
$ gcc -o test test.c -lpthread
$ ./mysystem ./test
This is test program!
code is 48.23
阻塞,部分信号被忽略,没有解决信号不会排队的问题。
8.24
参考资料:
8.18程序位于519。
代码:
/* $begin waitpid1 */
#include "csapp.h"
#define N 2
int main() 
{
    int status, i;
    pid_t pid;
    /* Parent creates N children */
    for (i = 0; i < N; i++)                       //line:ecf:waitpid1:for
	if ((pid = Fork()) == 0)  /* Child */     //line:ecf:waitpid1:fork
	    exit(100+i);                          //line:ecf:waitpid1:exit
    /* Parent reaps N children in no particular order */
    while ((pid = waitpid(-1, &status, 0)) > 0) { //line:ecf:waitpid1:waitpid
        if (WIFEXITED(status)) {                    //line:ecf:waitpid1:wifexited
            printf("child %d terminated normally with exit status=%d\n",
            pid, WEXITSTATUS(status));     //line:ecf:waitpid1:wexitstatus
        }else if(WIFSIGNALED(status)){
            // 返回信号编号
            char buf[100];
            sprintf(buf, "child %d terminated by signal %d: Segmentation fault\n", pid, WEXITSTATUS(status));
            psignal(SIGSEGV, buf);
        }else{
            printf("child %d terminated abnormally\n", pid);
        }
    }
    /* The only normal termination is if there are no more children */
    if (errno != ECHILD)                          //line:ecf:waitpid1:errno
	unix_error("waitpid error");
    exit(0);
}
/* $end waitpid1 */8.25
代码:
#include "csapp.h"
#define SIZE 100
sigjmp_buf env;
void handler(int sig){
    siglongjmp(env, 1);
}
char *tfgets(char *s, int size, FILE *stream){
    if (!sigsetjmp(env, 1)){
        alarm(5);
        Signal(SIGALRM, handler);
        char* res = fgets(s, size, stream);
        return res;
    }else{
        return NULL;
    }
}
int main(){
    char buf[SIZE];
    char* res = tfgets(buf, SIZE, stdin);
    if (res == NULL){
        printf("NULL\n");
    }else{
        printf("%s\n", res);
    }
    return 0;
}测试:
$ gcc -o tfgets tfgets.c -lpthread
$ ./tfgets 
123
123
$ ./tfgets 
NULL本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
 评论
ValineLivere
