0% found this document useful (0 votes)
18 views5 pages

HW2 SolutionsSMU

The document contains solutions for a homework assignment on operating systems, focusing on process creation, multithreading, and the effects of fork and exec system calls. It includes code analysis, examples of multithreading benefits, and calculations using Amdahl's Law. Additionally, it explains the output of various programs involving child and parent processes, demonstrating how memory is handled in forked processes.

Uploaded by

parth.phd1539
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views5 pages

HW2 SolutionsSMU

The document contains solutions for a homework assignment on operating systems, focusing on process creation, multithreading, and the effects of fork and exec system calls. It includes code analysis, examples of multithreading benefits, and calculations using Amdahl's Law. Additionally, it explains the output of various programs involving child and parent processes, demonstrating how memory is handled in forked processes.

Uploaded by

parth.phd1539
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

CS5/7343 Operating Systems

Fall 2024
Homework 2 - Solutions
Due: September 30, 2024, at 11:59 PM

1. [20 points] Analyze the following C code. How many total processes are created when the program in Figure
1 runs? Support your answer with a process tree diagram.
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>

int main()
{
pid_t p, q, r, s;
printf("before fork 1\n");
p=fork();
printf("before fork 2\n");
q=fork();
printf("before fork 3\n");
r=fork();
printf("before fork 4\n");
s=fork();
}
Figure 1

Answer:

The total number of processes = 16


#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
pid_t pid;

/* fork a child process */


pid = fork();

if (pid &lt; 0) { /* error occurred */


fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
execlp("/bin/ls","ls",NULL);
printf("LINE 123");
}
else { /* parent process */
/* parent will wait for the child to complete */
wait(NULL);
printf("Child Complete");
}
return 0;
}

Figure 2
2. [10 points] a) Ordinarily the exec() system call follows the fork(). Explain what would happen if a programmer
were to inadvertently place the call to exec() before the call to fork().
2. [10 points] b) Explain the circumstances under which the line of code marked printf("LINE 123") in the figure
below (correction: Figure 2) will be reached.

Answer:

a) Because exec() overwrites the process, we would never reach the call to fork() and hence, no new
processes would be created. Rather, the program specified in the parameter to exec() would be run
instead.
b) The line of code marked printf("LINE 123") will be never be reached unless the line of code marked
execlp("/bin/ls","ls",NULL) is removed.

3. [10 points] a) Provide three programming examples in which multithreading provides better performance
than a single-threaded solution.
3. [10 points] b) Using Amdahl's Law, calculate the speedup gain of an application that has an 80 percent parallel
component for (i) two processing cores and (ii) four processing cores. Show your calculations.
Answer:
a) Some possible examples:
• Web server handling multiple client requests. A multithreaded web server spawns a new
thread (or reuses a thread from a pool) for each incoming client request. Each thread handles
the connection with its client independently.
•Matrix Multiplication. Divide the task of matrix multiplication across multiple threads, where
each thread computes a subset of the result matrix. Since matrix multiplication is
embarrassingly parallel (each row-column product is independent), this results in significant
speedup on multi-core systems.
• Parallel Image Processing: Applying filters to different parts of an image concurrently speeds
up the task.
b) Amdahl’s Law

(i) N = 2, S=20%,
speedup <= 1/(0.2 + (1-0.2)/2)
speedup <= 1/(0.2 + 0.4)
speedup <= 1/(0.6)
speedup <= 1.67

(ii) N = 4, S=20%,
speedup <= 1/(0.2 + (1-0.2)/4)
speedup <= 1/(0.2 + 0.2)
speedup <= 1/(0.4)
speedup <= 2.5
4. [20 points] The program shown in Figure 3 uses the Pthreads API. Explain what the output will be at
lines A and B.
#include <pthread.h>
#include <stdio.h>

int value = 0;
void *runner(void *param); /* the thread */

int main(int argc, char *argv[])


{
pid_t pid;
pthread_t tid;
pthread_attr_t attr;

pid = fork();

if (pid == 0) { /* child process */


pthread_attr_init(&attr);
pthread_create(&tid, &attr, runner, NULL);
pthread_join(tid,NULL);
printf("CHILD: value = %d",value); /* LINE A */
}
else if (pid > 0) { /* parent process */
wait(NULL);
printf("PARENT: value = %d",value); /* LINE B */
}
}
void *runner(void *param) {
value = 5;
pthread_exit(0);
}

Figure 3
Answer:
Line A output:
CHILD: value = 5
Line B output:
PARENT: value = 0

The child process creates a thread that runs runner(), and this thread sets value = 5 in the child process’s
memory. The parent process continues execution after the wait(NULL) call, but since it has its own copy
of value (which wasn’t changed), it still sees value = 0.

In other words, even though value is global, it exists in two separate memory spaces after the fork() — one for
the parent and one for the child. Changes to value in the child process do not propagate to the parent.
5. [20 points] Using the program shown in Figure 4, explain what the output will be at lines C and D.

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

#define SIZE 5

int nums[SIZE] = {0,1,2,3,4};

int main()
{
int i;
pid_t pid;

pid = fork();

if (pid == 0) {
for (i = 0; i < SIZE; i++) {
nums[i] *= -i;
printf("CHILD: %d ",nums[i]); /* LINE C */
}
}
else if (pid > 0) {
wait(NULL);
for (i = 0; i < SIZE; i++)
printf("PARENT: %d ",nums[i]); /* LINE D */
}
return 0;
}

Figure 4
Answer:
Line C output:
CHILD: 0 CHILD: -1 CHILD: -4 CHILD: -9 CHILD: -16
Line D output:
PARENT: 0 PARENT: 1 PARENT: 2 PARENT: 3 PARENT: 4

There is a global array nums of size 5: int nums[SIZE] = {0, 1, 2, 3, 4};.


The fork() system call is used to create a child process, resulting in two processes: a parent and a child.
Both processes will have their own copies of the nums array due to how fork() works (each process gets a
separate copy of the parent's memory at the time of fork()).

The child process enters the if (pid == 0) block.


It modifies the array nums by multiplying each element by -i, where i is the index.
The parent process waits for the child to finish with wait(NULL) and then prints the nums array at Line D.
Since the parent and child have separate memory spaces, the changes made by the child process to nums do
not affect the parent's copy of nums.

You might also like