COMPSCI 377 LAB: Fork and Exec

Purpose

This lab is designed to introduce you to processes. Using various system calls in C++, we can create and modify processes to further help our code. Please make sure that all of your answers to questions in these labs come from work done on the Edlab environment – otherwise, they may be inconsistent results and will not receive points.

The TA present in your lab will do a brief explanation of the various parts of this lab, but you are expected to answer all questions by yourself. Please raise your hand if you have any questions during the lab section. Questions and Parts have a number of points marked next to them to signify their weight in this lab’s final grade.

Please read through this lab and follow the instructions. After you do that, visit Gradescope and complete the questions associated with this lab by the assigned due date.

You may work in groups up to 3 to complete this lab. Make sure you submit as a group in Gradescope.

Setup

Once you have logged in to Edlab, you can clone this repo using

git clone <https://github.com/umass-cs-377/377-lab-fork-exec.git>

Then you can use cd to open the directory you just cloned:

cd 377-lab-fork-exec

This repo includes a Makefile that allows you to locally compile and run all the sample code listed in this tutorial. You can compile them by running make. Feel free to modify the source files yourself, after making changes you can run make again to build new binaries from your modified files. You can also use make clean to remove all the built files, this command is usually used when something went wrong during the compilation so that you can start fresh.

Part 1: Pointers (10 Points)

When programming in C++, we will frequently make use of pointers. Every variable that we make use of in this class has a memory location, which we can access through the & operator. When we have such a memory location, we can then access its stored value through the * operator. We use this same operator when declaring our pointers in the code. As an example, take the following code:

#include <string>
#include <iostream>using namespace std;

int main() {
	int original = 1; //variable that stores an integer value of 1
	int *pointer = &original; //variable that stores the memory address of ‘original’

	cout << original << "\\n"; //prints out the stored value of original: “1”
	cout << pointer << "\\n"; //prints out the stored value of pointer (some memory address)
	cout << *pointer << "\\n"; //prints out the stored value of the variable at the location of pointer (original): "1"

	//Code goes here

	return 1;
}

As can be seen in the code, pointers allow for a lot of memory reference to be carried out in C++. We can also combine multiple operators together. This means that &(*pointer) will result in just pointer, but there could be problems if *(*pointer) is called, since that would be looking at the data stored with memory address of *pointer. In general, using (*variable) for something such as variable = 1 will throw an error.

Part 2: Fork (10 Points)

The fork() command makes a complete copy of the currently running program, running from the same state in which the function was called. For these two copies, we are able to determine which process is the original through the value returned by the fork() command, called the process ID. Process IDs are used by operating systems to identify active processes – when a process runs, the process ID of the next process to start will increment by 1. This means that if we run one process with process ID 22100, and then run 999 more processes on the system, the next process will have a process ID of 23100 instead. As we will see, these IDs allow us to manipulate processes to help us with new actions in our code. Within C++ code, we can use the getpid() command to get the current process id of the process. As an example, take the following code: