CS 105

Write and Test Your Code

Time to write some code!

Remember that all of your work will be done in the file ringbuf.c.

  1. Start by opening up ringbuf.c in your editor. Make sure that the names of both partners are included in comments at the top of the file.
  2. Check the ringbuf Specification for the details about what your code should do.

There are some hints further down in the page.

Compiling and Testing

We have provided a sample Makefile that will compile your program. Pay attention to compiler warnings—and fix them!

To test your program, run it with standard input redirected to a test file. For example,

./ringbuf < testinput1.txt

The lab tar file includes five test files for you to try out:

testinput0.txt
A small test case with no sleeping. Note that because of indeterminacy in the system scheduler, this test file may produce different results from run to run. However, only it and testinput4.txt will ensure that you are interpreting print_code correctly.
testinput1.txt

The test case from testinput0.txt, with 1-second sleeps for the producer and no sleeping in the consumer. We recommend that you begin testing with this file, because it generates results that are easy to interpret. Also, be sure that it produces exactly one pair of output lines per second. If the output comes along too quickly, or if your program appears to hang, you may be calling nanosleep incorrectly. (Hint: if you run

time ./ringbuf < testinput1.txt

it should report a “real” time of about 25 seconds.)

testinput2.txt
The test case from testinput0.txt, with 1-second sleeps for the consumer and no sleeping in the producer. This file tests your ability to deal with situations where the producer runs far ahead of the consumer, so that the buffer is always full.
testinput3.txt
A test case with randomly generated sleep times. At times, the producer will run ahead; at other times the consumer will catch up.
testinput4.txt
Another test case with randomly generated sleep times, and also with randomly generated print_codes.

We also provide two sample outputs; your output should match them exactly. You can check for correctness with the command

./ringbuf < testinput1.txt | diff testoutput1.txt -

and similarly for testinput2.txt. The diff command will be silent if things match; otherwise it will tell you what lines are different. Watch out for whitespace errors!

Sample Output

The following is the result of running our sample solution on the test case testinput4.txt (note that your interleaving of “Produced” and “Consumed” messages may differ, because this test input has randomness built in):

Produced -8 from input line 2
Consumed 3 from input line 1; sum = 3
Produced 1 from input line 3
Produced 10 from input line 4
Consumed 1 from input line 3; sum = -4
Consumed 4 from input line 5; sum = 10
Produced 0 from input line 6
Consumed 0 from input line 6; sum = 10
Produced -1 from input line 8
Consumed -1 from input line 8; sum = 3
Consumed 8 from input line 9; sum = 11
Consumed 5 from input line 12; sum = 20
Produced 10 from input line 14
Consumed 1 from input line 15; sum = 40
Produced 10 from input line 16
Produced 5 from input line 17
Produced -2 from input line 20
Produced 1 from input line 21
Consumed -2 from input line 20; sum = 48
Consumed 9 from input line 23; sum = 53
Consumed 3 from input line 24; sum = 56
Produced 6 from input line 26
Consumed 6 from input line 26; sum = 55
Produced -3 from input line 27
Produced -8 from input line 32
Consumed -4 from input line 30; sum = 47
Consumed -7 from input line 31; sum = 40
Consumed -8 from input line 32; sum = 32
Consumed -4 from input line 34; sum = 34
Produced -7 from input line 36
Produced -1 from input line 39
Consumed 3 from input line 40; sum = 45
Consumed 1 from input line 41; sum = 46
Produced 10 from input line 42
Produced 0 from input line 43
Consumed -2 from input line 44; sum = 54
Produced -8 from input line 46
Consumed -8 from input line 46; sum = 39
Produced 1 from input line 49
Consumed -8 from input line 47; sum = 31
Consumed -1 from input line 48; sum = 30
Consumed 1 from input line 49; sum = 31
Consumed 11 from input line 50; sum = 42
Final sum is 42

Hints

Pthreads Features

You will need to familiarize yourself with the following pthreads functions, at a minimum:

  • pthread_create
  • pthread_join
  • pthread_mutex_lock
  • pthread_mutex_unlock
  • pthread_cond_wait
  • pthread_cond_signal

You may choose to use other functions as well. Remember that you are NOT allowed to use the pthreads semaphore functions (sem_*).

Sleeping

For historical reasons, there are many ways to get a thread to go to sleep for a specified time period. The preferred method is nanosleep; see man 2 nanosleep for documentation. Note that if the sleep time exceeds 999 milliseconds, you cannot simply convert milliseconds to nanoseconds because nanosleep requires that the nanoseconds field be less than \( 10^9 \). Also note that you will not need the second argument to nanosleep; you can set it to NULL. We have provided a wrapper function named thread_sleep that accepts an argument in milliseconds and converts it into a correct nanosleep call. However, note that as given, the wrapper function does not work correctly: it always sleeps for 0.25 seconds. You will have to modify it to calculate a correct value.

Also note that if the specified sleep time is zero, the wrapper function doesn't call nanosleep.

To Complete This Part of the Assignment

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)