8.9
进程对 |
并发? |
---|---|
AB |
否 |
AC |
是 |
AD |
是 |
BC |
是 |
BD |
是 |
CD |
是 |
8.10
A
fork
B
execve
,longjmp
C
setjmp
8.11
4
8.12
8
8.13
x=4
x=3
x=2
8.14
3
8.15
5
8.16
counter = 2
8.17
三种可能性。
1
Hello
0
1
Bye
2
Bye
2
Hello
1
0
Bye
2
Bye
3
Hello
1
Bye
0
2
Bye
8.18
A,C,E
8.19
8.20
#include <unistd.h>
using namespace std;
int main(int argc, char* argv[], char* envp[])
{
execve("/bin/ls", argv, envp);
}
不明白意义何在,练习如何使用execve
么。。
8.21
abc
或bac
8.22
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
void unix_error(char* msg){
fprintf(stderr, "%s : %s\n", msg, strerror(errno));
}
pid_t Fork(){
pid_t pid;
if((pid = fork()) < 0)
unix_error("Fork error");
return pid;
}
int mysystem(char* command){
pid_t pid = Fork();
if(pid){
int status;
wait(&status);
if(WIFEXITED(status))
return WEXITSTATUS(status);
if(WIFSIGNALED(status))
return WTERMSIG(status);
}else{
char* argv[] = {"/bin/sh", "-c", command, NULL};
execve("/bin/sh", argv, NULL);
}
}
int main(int argc, char* argv[], char* envp[])
{
printf("exit code: %d\n", mysystem(argv[1]));
fflush(stdout);
}
mac上好像ctrl+c
无法触发,通过资源监视器杀进程可以触发非正常退出的分支。
8.23
信号量不会排队,当子进程给父进程发送信号时,第一个信号会被接受并且处理,第二个信号会被记录并且等待第一个信号处理完成,其他的信号都会被简单地丢弃。
所以正如教材前面所说的,不能使用信号量对其他进程中的某些东西计数。
8.24
#include "csapp.h"
#define N 2
int main(){
int status, i;
pid_t pid;
/* Parent creates N children */
for(i = 0; i < N; i++)
if((pid = Fork()) == 0){
int* p = 0x0;
*p = 1;
exit(0);
}
/* 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)){
Sio_puts("child ");
Sio_putl(pid);
psignal(SIGSEGV, " terminated by signal 11");
}
}
/* The only normal termination is if there are no more children */
if(errno != ECHILD)
unix_error("waitpid error");
exit(0);
}
运行输出:
child 42018 terminated by signal 11: Segmentation fault
child 42019 terminated by signal 11: Segmentation fault
一开始没看懂题目意思,看懂后阅读psignal
相关资料就可以完成,注意使用printf
会出问题,因为printf
并不是安全的,这里使用的是Sioputs
和Sioputl
,也可以使用sprintf
先写到缓冲区然后利用psignal
进行输出。
8.25
#include "csapp.h"
sigjmp_buf buf;
void sigchld_handler(int sig){
siglongjmp(buf, 1);
}
char* tfgets(char* str){
if(sigsetjmp(buf, 1))
return NULL;
pid_t pid;
if(signal(SIGCHLD, sigchld_handler) == SIG_ERR)
unix_error("set SIGCHLD error");
if((pid = Fork()) == 0){
sleep(5);
exit(0);
}else{
return gets(str);
}
}
int main(){
char buf[256];
puts(tfgets(buf));
}
首先得开一个子进程对五秒时间进行计数,如果子进程成功返回说明超时应该返回NULL
,不然直接返回gets
的结果就行。
所以父进程应该直接调用gets
满足不超时的情况,问题在于超时后父进程捕捉到子进程结束时的仍在等待gets
,而signal handler
只能返回到当前指令无法对流程进行控制,这时候就应该使用非本地跳转返回到注册地进行处理。
理论上感觉goto
也是可以的,由于实用性不高没有进行尝试。
8.26
其实就是shell lab
,等待完成中。