WEEK 8 TEST: PROCESS FANS AND THE SELECT SYSTEM
CALL
PROFESSOR GODFREY MUGANDA
CSC 4/527
1. Project Overview
For this test, you will learn about an important system call and apply it to solving
an inter-process communication problem involving process fans.
You will write a main (driver) program main.cpp that is able to run other (slave)
programs whose names are passed on the command line. These programs in turn
also take their arguments from the command line. In fact, each program will take
a single integer argument on the command line and write its output to its standard
output.
The driver program will create a child process to run each of the programs specified
on its command line, as well as pipes to communicate with the children. The driver
will pass each child program the appropriate command line argument. As the
children start producing output, the driver program will read whichever pipe is
ready and write what it reads to the screen, taking care to identify the program
the output came from.
Each of the slave program produces a succession of the first n terms of a sequence.
The number of terms of the sequence is whatever is specified on the command line.
2. Example Output
There will be at least 5 slave programs:
(1)
(2)
(3)
(4)
(5)
factorial
odd
even
square
cube
Here are 2 examples of running the driver program. In the first example, the driver
runs a single slave:
./main cube 7
cube 1
cube 8
cube 27
cube 64
cube 125
cube 216
cube 343
In the second example, the driver runs three slaves
1
2
PROFESSOR GODFREY MUGANDA CSC 4/527
./main cube 7 square 4 factorial 6
square 1
factorial 1
square 4
cube 1
factorial 2
square 9
square 16
cube 8
factorial 6
factorial 24
cube 27
cube 64
factorial 120
cube 125
factorial 720
cube 216
cube 343
Basically, the slaves run at different speeds, so data they produce will arrive at the
master at different rates. The master outputs data as it arrives
3. Structure of the Slaves
Each program will take a positive integer n on the command line and output, in
a leisurely fashion, the first n terms of the corresponding sequence. Here is one of
the programs, cube.cpp
#include <cstdlib>
#include <iostream>
using namespace std;
/*
*
*
*
*/
int
{
This program is a filter. It takes a value n passed on the command line
and outputs a sequence of the first n terms of the cube sequence.
Of course n should be a positive integer.
main(int argc, char** argv)
int cube(int);
void process(int (*)(int), int);
if (argc != 2)
{
cerr << "Usage " << argv[0] << " number
return 1;
}
int n = atoi(argv[1]);
process(cube, n);
return 0;
}
";
WEEK 8 TEST: PROCESS FANS AND THE SELECT SYSTEM CALL
3
int cube(int n)
{
return n*n*n;
}
void process( int(*f)(int), int n)
{
sleep(f(3) % 4);
for (int k = 1; k <= n; k++)
{
int result = f(k);
write(1, &result, sizeof(int));
sleep(rand() %3);
}
}
Note that the program computes and writes the first n cubes to its standard output,
in binary form. If you run this program, the output on the screen will look like
garbage.
Use this pattern for all the slave programs. Note that all you need to do is to
replace the sequence function and make some very minor changes.
4. The Select System Call
Use the select system call in your main driver program to handle the concurrent
inputs from the childrens’ pipes. You can find a discussion of the select system
call in section 4.4 of the class textbook. The example of Program 4.13 on page 111
is particularly helpful.
5. Hints
The structure of the driver program consists of
(1) creating n pipes to talk to the n children,
(2) appropriately forking the children, closing a subset of the pipes in each
child, and invoking execl to run the right programs in the child processes,
(3) closing a subset of the pipes in the parent process, and
(4) using select to get the data being sent by the children.
A good way to go about this is to do all steps but the last, and then test the code
you have with only one child. That way, you only have one pipe to read and there
is no need for the select call. Once you have it working with one child, replace
the code for reading the child pipe and printing the results with appropriate code
that uses select to read all the pipes as they become ready.
The driver program should flush standard output after writing each line of output.
One way to do this is to use the C++ code similar to
cout << pipe_to_prog[*it] << " " << value << "\n" << flush;
Or you can just output to standard error.
4
PROFESSOR GODFREY MUGANDA CSC 4/527
I recommend the use of C++ and the standard template library, except for those
of you that love to program in C and build your own data structures. If you
are programming in C++, you can use an object of the map class to associate a
child pipe input file descriptor with the name of the program the child process is
executing. In the example above, pipe to prog is a map and *it is an iterator
referencing a file descriptor stored in a vector of int.
You can also use vector<int> from the standard template library to hold file
descriptors that have not yet arrived at end of file. Say you have such a vector fds.
You will use select in a loop. Each iteration of the loop puts all file descriptors
in fds into a read set to pass to select. After select returns, each file descriptor in
fds is checked to see if it is ready for input. Read a single integer from each ready
file descriptor, output a single line of output, and move to the next iteration of the
loop. A file descriptor is removed from fds when it is ready and it is found to be
at end of file. You are done when the fds vector becomes empty.
6. Submission
This is due Thursday of week 9 at midnight. Submit a zipped up folder with all
source files: the main file, as well as the source files for the slave programs.
© Copyright 2026 Paperzz