You are on page 1of 4

Lab 08 CIS 370 Due: Week of 11/12/2018

More on IPCs: Pipes and Shared Memory


Objective
To better understand the use of pipes and shared memory to communicate between processes.

Submission:
- One compressed file that contains all C and pdf files
- Make sure to do the following:
- Check the success of every system call you use
- When using pipes, make sure to close the pipe-side the process will not use

Description
1. Send messages to child processes:
Write a C program that creates 2 child processes (C1 and C2) and 2 pipes. The parent process will
facilitate sending any number of messages from the user to either of the child processes as shown in
Figure 1 below.

Parent

C2
C1

Figure 1: Communication between a parent and 2 child processes

The parent process reads the ID of the destination process as well as the message itself from the user
and sends the message through the correct pipe to its intended destination. The parent, being the
sender process, ignores any messages that are destined to neither of the two child processes. As soon as
a child process receives a message it prints it to the screen as shown in the sample run below (Figure 2).
The parent process will keep on reading messages from the user and sending them to the destination
processes until the user types -1 for the ID of the destination. It then closes all open pipes and
terminates. Make sure to test for the success of the different system calls you use in your code and that
the parent process waits for its children before it terminates.

Test your code by changing the pipe() system call to pipe2() and test the behavior of your program
when you set the non-blocking flag O_NONBLOCK.

Note: All labs are due before next week’s lab starts
Lab 08 CIS 370 Due: Week of 11/12/2018

Your program should behave as follows:

- After opening the pipes and creating the children, the parent process should prompt the user
for the messages in the form: "<child_to_receive_msg> <one_word_message>":
- You may assume that messages are only one word in length (you do not need to handle spaces
in messages).
- The parent will then use pipes P1 and P2 to send all the messages to the appropriate children.
- Each process should ensure that its pipes are unidirectional.
- Once received, a message is printed out in the form:
---> Child 1 received: msg_1_to_child_1

A sample run is shown in Figure 2 below:

- 3 messages are sent to child process 1. These messages are received and printed by process 1.
- 2 messages were sent to child process 2. The messages were received and printed by process 2.
- A message was sent to process 7. It was ignored and an error message was printed by the
parent process.
- The process terminates as soon as the user types -1 and hits enter.

Figure 2: A sample run of the program

Hints:
- To avoid blocking reads in the children, you should consider what happens when processes close
one end of a pipe.
- To guarantee the order of printing to the screen make sure that the parent process sleeps for a
fraction of second. Investigate using the function usleep().
- Assume a maximum message size of 64 bytes.

Note: All labs are due before next week’s lab starts
Lab 08 CIS 370 Due: Week of 11/12/2018

2. Exchange PIDs among processes from the same parent:


Write a C program that creates 2 child processes (C1 and C2). The processes will exchange their PIDs
through the parent process:
- Each child will get its PID and send it to the parent process. The parent process will read the PIDs
of the children and forward them:
o Read C1 PID through c1_to_p, and writes to C2 through p_to_c2.
o Reads C2 PID through c2_to_p, and writes it to C1 through p_to_c1.

Parent

C1 C2

Figure 3: 2 child processes exchange their PIDs through their parent

Hints:
- Create 4 pipes in the parent process.
- Be careful when closing the pipe ends your process does not need.
- Keep in mind that pipes are byte streams so make sure to properly cast the values you are
sending through the different pipes. See example below:
int C1_PID, someIntVar;
write(c1_to_p[1], (int *) &C1_PID, sizeof(C1_PID));
……….
read(c1_to_p[0], (int *) &someIntVar, sizeof(someIntVar));

3. Using shared memory to communicate between a producer and a consumer process:


Write a C program that will produce items and place them in a shared buffer and another program
that will read these items and consume them (i.e. process them). The 2 processes will use a shared
memory to represent the buffer that the producer will write to and the consumer will read from.
Since the speeds of the processes are different, the shared memory should also have 2
variables/pointers (in, out) that both processes can access and use to synchronize the use of the
buffer:
o When in = out: buffer is empty of new items, and reader should stop;
o When in+1 = out: buffer is full, and writer should stop;
Refer to slides 15-17 in “Lec_04_b Communication Between Processes“ for More details on
how the producer and the consumer processes should function .

Use the following data structure to represent the data that will be shared between the producer and
the consumer processes:

Note: All labs are due before next week’s lab starts
Lab 08 CIS 370 Due: Week of 11/12/2018

#define MAX_SIZE 8
typedef struct bufferStruct {
int in;
int out;
int content[MAX_SIZE];// will hold ASCII calues of characters
}bufferStruct;

- Every time the user hits enter in the producer process, it should generate random integer value
and store it into the shared buffer until the buffer is full. If the user hits enter after that then a
“buffer is full …” error message should be printed.
- Every time the user hits enter in the consumer process, it should consume the oldest item in the
buffer and print it to the screen, until the buffer is empty. If the user hits enter after that then a
“buffer is empty …” error message should be printed.
- Both programs should terminate if the user enters a ‘0’;

#ifndef BUFFER
#define BUFFER

#define MAX_SIZE 8

typedef struct bufferStruct

int in;
Time

int out;
int content[MAX_SIZE];
}bufferStruct;

key_t someKey = 1111;

#define memorySize sizeof(bufferStruct)


#endif

int pipe(int filedes[2]);


int pipe2(int fildes[2], int flags);
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int usleep(useconds_t usec);
int shmget(key_t key, size_t size, int flag);
void * shmat(int shmid, const void *addr, int flag);
int shmdt(const void *addr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

Note: All labs are due before next week’s lab starts

You might also like