8.9
About the definition of parallelism I've written an article before, for reference:
The difference between concurrency and parallelism 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 plays
+--------------> printf("hello\n") | | Fork | i = 1 +------------+--------------> printf("hello\n") | | | +--------------> printf("hello\n") | | | | | |+--------+------------+--------------> printf("hello\n") Fork Fork i = 0 i = 1
8.12
8 plays
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
Guaranteed x=4 before x=3 (topological sort), there are three scenarios:
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 plays
+-------> printf("hello\n") +---> | +-----+-------> printf("hello\n") +---> | Fork Fork| main +-------------------------------------------------> printf("hello\n") |+----+ doit()
8.15
5 plays
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
Assuming that the child process exits normally, there are three scenarios in which the topology can be sorted:
A.
Hello 1 Bye 0 2 Bye
B.
Hello 1 0 Bye 2 Bye
C.
Hello 0 1 Bye 2 Bye
8.18
Make the topology sort, ace right.
The first one in B cannot be 2. There cannot be two 2 behind the first 1 in D.
+-->printf("0")+--->printf("2") | +----->atexit+-+-->printf("1")+--->printf("2") | Fork | Fork+---+--------------+-->printf("1") Fork | +-->printf("0")
8.19
2^n
Each fork will double the number of the original process, and the last process will output one line, so it is 2^n.
8.20
The book says changing the columns environment variable will ls
change the width of the output, but export
after changing the environment variable on my machine, if I call again ls
, it is still output as the width of the terminal, and columns is changed back to the original value, I suspect is called ls
the system re-detects the end width and sets a new columns.
#include <unistd.h>#include <errno.h>#include <stdio.h>int main(intconstcharconstchar *envp[]){ if (execve("/bin/ls", argv, envp)) { perror("Failed to execve /bin/ls:\n"); } return0;}
Type inconsistencies may alert you, there is no problem here.
8.21
To meet the topological sort, there are two situations:
A.
Abc
B.
Bac
+----->printf("a")+-------+ | | | v+---+----->printf("b")+--->waitpid+--->printf("c")+--> fork
8.22
According to man 3 system
the section description:
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);
We can get execl
the process diagram after the call:
According to man sh
the section description:
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.
You can see Otherwise the shell will return the exitstatus of the last command executed this sentence, that is, the command execution state would be called sh
the return form State, so we recycle sh
and judge its return status.
#include <sys/wait.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>intMysystem (Char*command) {pid_t sh_pid;intSh_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)) {returnWexitstatus (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", ); }returnWtermsig (Sh_status); }Else{fprintf (stderr,"command terminated abnormally.\ n"); fprintf (stderr,"Return status information ...\ n");returnSh_status; } }Else{fprintf (stderr,"Failed to reap/bin/sh.\ n");returnExit_failure; } }}
8.23
A typical signal can not be summed up the problem.
When a child process sends 5 signals to the parent process consecutively, the SIGUSR2
first signal transfer process is as follows, where a represents the child process and C represents the parent process:
When the parent process C receives the signal, it enters the signal processing function, and temporarily blocks the signal (setting the block bit), and the child process continues to send all the remaining similar signals to the parent process, the pending bit is reset 1 again, and the next signal is discarded (only one pending bit, No way to count), when the parent process C signal processing function exits, the block bit is zeroed, just pending signal is sent to the parent process C again, the parent process again into the signal processing function, the child process has completed all the signal sent, so the parent process will not enter the signal processing function again. In summary, parent process C will only enter two signal processing functions, that is, counter will only be added 2 instead of 5.
8.24
The book says to use psignal
the description of the library function signal, which is man 3 psignal
described as follows:
#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.
Change the code for figure 8.18 to:
#include <stdio.h>#include <signal.h>#include <sys/wait.h>#include <sys/types.h>#include <errno.h>#include <unistd.h>#define N 2intMain () {intStatus pid_t pid; for(inti =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 (status), Wtermsig," "); }Else{fprintf (stderr,"Child%d terminated abnormally with status information=%d\ n", PID, status); } }if(errno! = echild) {fprintf (stderr,"Waitpid Error"); }return 0;}
Run output:
8.25
The countdown can be alarm
implemented, and it will raise a signal after a specified time SIGALRM
, man 2 alarm
partly describing:
#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.
After we receive this signal, we will find a way to terminate the read in the wait and return null. One way is to use setjmp.h
, we enter the normal read in the first use setjmp(buf)
(this time the setjmp
return value is 0), but when the signal appears (the time cutoff), the signal processing function will longjmp(buf,1)
(the setjmp
return value is 1), depending on the return value, then we enter return NULL
statement.
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <setjmp.h>#define TIMEOUT ((unsigned int) 5)#define SIZEOFBUF 1024x768Jmp_buf buf;voidSigalrm_handler (intSignum) {longjmp (buf,1);}Char*tfgets (Char*s,intSize, FILE *stream) {if(Signal (SIGALRM, sigalrm_handler) = = Sig_err) {Perror ("Failed to install Sigalrm_handler");returnNULL; }Else{Alarm (TIMEOUT);/ * Raise SIGALRM after TIMEOUT seconds * /}if(!SETJMP (BUF)) {returnFgets (s, size, stream); }Else / * longjmp from Sigalrm_handler * /{returnNULL; }}intMainintargcChar Const*argv[]) {CharTEMP_BUFER[SIZEOFBUF];Char*result = Tfgets (Temp_bufer, Sizeofbuf, stdin);if(Result) {printf ("Input:%s\ n", result); }Else{fprintf (stderr,"Time out!\ n"); }return 0;}
Run output (second input timeout):
8.26
The four-star topic is actually the Shelllab (TSH) experiment in this chapter, and I will post the writeup link to the experiment.
In-depth understanding of computer systems _3e the eighth chapter of homework CS:APP3E Chapter 8 Homework