System Calls

Description of system calls for shared memory and semaphores

Description fork system calls

Concurrency

This assignment must be written in C.

The purpose of this assignment is to give you some "hands-on" experience with concurrent processes, semaphores, and shared memory. The program is an implementation of the bounded, circular buffer Single Producer/Single Consumer problem. Use the Unix fork system call to spawn a child process that will run in parallel with the parent. The parent should become the Producer and the Child process should become the consumer. You will use a shared segment of 10 integers which will be treated as 10 integer buffers. For the size parameter to the shmget function, specify sizeof(int)*10. The producer will consist of a simple loop that cycles through the buffers, in order, depositing the first 1000 consecutive integers. The consumer will cycle through the buffers, "removing" items and summing the items removed. After consuming 1000 items, the consumer should print out the sum of the 1000 items consumed. Since the operating system buffers output, each time you print something, you must force the output to be displayed, not buffered. If you are using printf, each printf should be followed by: fflush(stdout). This will force the OS to display your output rather than buffering it for you.

You must synchronize the producer and consumer so that "your solution works." The producer must not produce additional buffers if all 10 buffers are full and the consumer must not consume buffers that do not contain valid data (empty or previously consumed). Your solution should, of course, contain no busy waits and should not unnecessarily restrict parallelism. The producer should always be trying to produce and the consumer should always be trying to consume. Each can only produce/consume if it is "ok" to do so. Again, the producer should loop until it has deposited all 1000 numbers. After the last deposit, it should print a message stating it is complete and waiting for the child to terminate. Be sure to force the print buffer to be emptied. The parent should then wait for the termination of the consumer, return the shared segment identifier and any shared semaphores.

For your design, see Figure 5-13. The code in Figure 5-13 is a high-level solution to producer/consumer problem that will work if shared variables are used. You are specifically solving the single producer/single consumer problem. The producer and consumer do not share variables. They only share the 10-byte buffer. As stated above, your solution must not unnecessarily restrict parallelism.

After the execution of the fork system call, you have two heavy-weight processes: the parent and the child. They do not share memory. The child has a copy of all of the data structures of the parent at the time of the fork. Therefore, any resources obtained from the operating system prior to the execution of the fork is known by both the child and the parent.
 

System calls usually return -1 if the call failed and set the global variable errno to the error returned by the kernel. The values that errno can take along with a brief description of each error can be found in the header file <sys/errno.h>.

At the completion of the processing, after waiting for the consumer to terminate, the producer should return the semaphores and the shared memory. This is very important as the system has a fixed number of semaphores and if you do not return them, others cannot use them and the system will eventually run out.

See the man pages for more information

Code Flow

In your main program, prior to executing the fork, you must get the shared segment, get ALL of the semaphores required by your program, and give ALL of the semaphores appropriate initial values.

Remember, the fork command gives the child process an exact copy (code and data) of the parent process at the time of the fork. Therefore, the child (consumer) knows everything it needs to know about the semaphores and shared memory segment.

The fork returns the child's pid to the parent and 0 to the child. Therefore, each process can determine its child/parent status.

The Producer (parent) and Consumer (child) must each attach the segment to their process.

The producer and consumer must each use the getpid system call to learn its process id. Prior to any processing, both the child and parent must print whether they are the parent or child and its pid. The producer and consumer should then loop producing and consuming as described earlier. When the producer has produced all items, it should wait for the consumer to terminate. After the consumer terminates, the producer should print a message, return the shared segment and all of the semaphores to the system.

The producer should use the wait system call to wait for the child: wait(&statloc); where statloc is an integer. See man pages for more information.

After the wait for the child to terminate returns, the parent must return the semaphores and shared memory.

Upon consumption of the 1000th item, the consumer must print the sum of the items and a message it is terminating, then terminate.

Semaphores and shared segments are "permanent." As you try to get your program to run, you will probably get some and your program will crash before it returns them. Use the system utility programs ipcs and ipcrm to clean up after yourself. If you do not, the system will run out of semaphores and/or shared segments and no one else will be able to get any (including you). Needless to say, your classmates (and others) will not be happy with you.
 
 

ipcs: report interprocess communication facilities status
 
 

ipcrm: removes a message queue, semaphore set, or shared memory ID.

You can also execute:
cs326clean

How to Get Started?

  1. Write a main program that simply gets a block of memory, attaches it, reads and writes it, then returns it.
  2. Add code to request a semaphore, assigns it an initial value of 1, waits on it, signals it, returns it.

What to hand in

  1. Use turnin to submit your assignment:
  2. After typing turnin, select prodconc.
  3. Your source file should be prodcon.c.
  4. Your source and output are worth 90 % of the grade for this assignment. Your program will be graded on its quality: neat, self-documenting, etc. Your code must produce correct output. Your program should always check the return values returned by system calls. There will be a penalty for not testing the return values of system calls. Why is this so? Your program must produce correct output.

  5. Write a report using a word processor:
    1. (10%) Describe how shared memory works. Describe the role of each semaphore and how synchronization is achieved. Although a formal proof is not required, you must provide a valid argument as to why your program is "correct" and does not unnecessarily restrict parallelism. .

Last modified 1:28 PM 11/07/2025

This page is copyright protected © by Barbara Bracken