深入理解计算机系统 第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 -lpthread
8.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
hello
8.13
子进程结果:
- 2
父进程结果:
- 4
- 3
父进程先结束:
4
3
2
子进程先结束:
2
4
3
或者:
4
2
3
8.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
hello
8.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
hello
8.16
子进程完成后退出,所以输出结果为:
counter = 2
验证:
$ gcc -o forkprob7 forkprob7.c -lpthread
$ ./forkprob7
counter = 2
8.17
8.4在520页,只要给出满足条件的拓扑排序即可:
Hello, 1, Bye, 0, 1, Bye
Hello, 1, 0, Bye, 1, Bye
Hello, 0, 1, Bye, 1, Bye
8.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
112002
8.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 c
8.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 4
8.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