$30.99
(Process Creation) [Taken from AY18/19 S1 Midterms]
C code:
00 01
02 03 04
05 06 07
08 09 10
11 12 13
14
int main( ) {
//This is process P if ( fork() == 0 ){ //This is process Q if ( fork() == 0 ) {
//This is process R
...... return 0;
} `
<Point α>
}
<Point β>
return 0;
}
Each of the following cases insert zero or more lines at Point α and β. Evaluate whether each described behaviour is correct or incorrect. (Note that wait() does not block when a process has no children.)
Point α
Point β
Behaviour
nothing
wait(NULL);
Process Q always terminates before P. Process R can terminate at any time w.r.t. P and Q.
wait(NULL);
nothing
Process Q always terminates before P. Process R can terminate at any time w.r.t. P and Q.
execl(valid executable....);
wait(NULL);
Process Q always terminates before P. Process R can terminate at any time w.r.t. P and Q.
wait(NULL);
wait(NULL);
Process P never terminates.
(Behavior of fork() system call) The C program below attempts to highlight the behavior of the fork() system call:
C code:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int dataX = 100; int main( )
{
pid_t childPID;
int dataY = 200;
int* dataZptr = (int*) malloc(sizeof(int));
*dataZptr = 300;
//First Phase
printf("PID[%d] | X = %d | Y = %d | Z = %d |\n", getpid(), dataX, dataY, *dataZptr);
//Second Phase childPID = fork();
printf("*PID[%d] | X = %d | Y = %d | Z = %d |\n", getpid(), dataX, dataY, *dataZptr);
dataX += 1; dataY += 2; (*dataZptr) += 3;
printf("#PID[%d] | X = %d | Y = %d | Z = %d |\n", getpid(), dataX, dataY, *dataZptr);
//Insertion Point (for parts (g), (h))
//Third Phase childPID = fork();
printf("**PID[%d] | X = %d | Y = %d | Z = %d |\n", getpid(), dataX, dataY, *dataZptr);
dataX += 1; dataY += 2; (*dataZptr) += 3;
printf("##PID[%d] | X = %d | Y = %d | Z = %d |\n", getpid(), dataX, dataY, *dataZptr);
return 0;
}
Please run the given program "ForkTest.c" on your system before answering the questions below.
What is the difference in how the 3 variables: dataX, dataY, dataZptr, and the memory location pointed to by dataZptr, are stored?
Explain the values that are printed by the program.
Focusing on the messages generated by second phase (they are prefixed with either "*" and "#"), what can you say about the behavior of the fork() system call?
Using the messages seen on your system, draw a process tree to represent the processes generated. Use the process tree to explain the values printed by the child processes.
Do you think it is possible to get different orderings between the output messages? Why?
Can you point out which pair(s) of messages can never swap places? i.e., their relative order is always the same?
If we insert the following code at the insertion point:
Sleep Code
if (childPID == 0){
sleep(5); //sleep for 5 seconds }
How does this change the ordering of the output messages? State your assumptions, if any.
Instead of the code in (g), we insert the following code at the insertion point:
Wait Code
if (childPID != 0){
wait(NULL); //NULL means we don’t care // about the return result }
How does this change the ordering of the output messages? State your assumption, if any.
(Parallel computation) Even with this crude synchronization mechanism, we can solve programming problems in new (and exciting) ways. We will attempt to utilize multiple processes to work on a problem simultaneously in this question.
You are given two C source code files: "Parallel.c" and "PrimeFactors.c". "PrimeFactors.c" is a simple prime factorization program. "Parallel.c" uses the
"fork()" and "execl()" combination to spawn off a new process to run
"PrimeFactors.c"
Let's setup the programs as follows:
Compile "c" to get an executable with the name "PF": gcc PrimeFactors.c –o PF
Compiles "c": gcc Parallel.c
Run the a.out generated from step (2). Below is a sample session:
$> a.out 1024
1024 has 10 prime factors //note: not unique prime factors
If you try large prime numbers, e.g. 111113111, the program may take a while.
Modify only Parallel.c such that we can now initiate prime factorization on [1-9] user inputs simultaneously. More importantly, we want to report results as soon as they are ready regardless of the user input order.
Sample session below:
$> a.out < test2.in
9 has 2 prime factors //Results
118689518 has 3 prime factors
44721359 has 1 prime factors
99999989 has 1 prime factors 111113111 has 1 prime factors
Note the order of the result may differ on your system. Most of time, they should follow roughly the computation time needed (composite number < prime number and small number < large number). Two simple test cases are given "test1.in" and "test2.in" to aid your testing.
Most of what you need is already demonstrated in the original Parallel.c (so that this is more of a mechanism question rather than a coding question). You only need "fork()",
"execl()" and "wait()" for your solution.
After you have solved the problem, find a way to change your wait() to waitpid(), what do you think is the effect of this change?
Additional Questions (For exploration only, not for tutorial discussion)
(Process Creation) Consider the following sequence of instructions in a C program:
C code:
int x = 10; int y = 123;
y = fork(); if (y == 0) x--;
y = fork(); if (y == 0) x--;
printf("[PID %d]: x=%d, y=%d\n",getpid(),x ,y);
You can assume that the first process has process number 100 (and so getpid() returns the value 100 for this process), and that the processes created (in order) are 101,102 and so on.
Give:
A possible final set of printed messages.
An impossible final set of printed messages.