CMSC 421: Principles of Operating Systems

Homework 3: SuperDuperUber

This homework is due on Tuesday, March 8, at 11:59:59 PM (Eastern standard time). You must use submit to turn in your homework like so: submit cs421_jtang hw3 hw3.c

Your program must be named hw3.c, and it will be compiled on Ubuntu 14.04 as follows:

  gcc --std=c99 -Wall -O2 -pthread -o hw3 hw3.c
There must not be any compilation warnings in your submission; warnings will result in grading penalties. In addition, your code must be properly indented and have a file header comment, as described on the coding conventions page.

In this homework, you are a programmer for the SuperDuperUber ride-sharing company. In town are several hotels popular with college students on Spring Break. Students summon rides to take them from one hotel to another; it is your responsibility to process the ride requests as quickly as possible. You have at your disposable a set number of cars to handle all of the requests.

Part 1: Starting Up

Your C program must accept three command-line arguments: number of cars available, name of a data file, and a random seed:

The general flow for your program must be:

  1. Initialize all global data values, including a pseudo-random number generator (PRNG). Call srand() with the seed specified by the last command-line parameter to seed the PRNG.
  2. Spawn the requested number of threads.
  3. Then in the main thread, open the given data file. For each entry within, parse the line and add the ride request to a pool of requests. Then send a message to the threads, indicating new work exists.
  4. Each car thread runs the same loop. Within that loop, a thread sleeps until a new work message is received. It takes the first available ride request and handles it.
  5. When the main thread runs out of requests, set a global flag and then awaken all other threads. Each car thread checks the flag, prints some statistics, then terminates itself.
  6. The main thread waits for all car threads to terminate. Finally, as proof that your program has correctly handled all requests, the main thread displays how many people are at each hotel at the end of the day.

Part 2: Threading

The SuperDuperUber company has a fleet of cars to handle ride requests. Your program spawns a number of threads, based upon the command line, for each car.

For this assignment, you are to implement the classic producer/consumer model. The main thread will be the producer. Its job is to parse the data file and generate requests. The newly created threads are consumers; they handle the requests. Tying everything together is a common request pool. This pool is a global data structure that can hold an arbitrary number of requests. Note that there is no maximum size for the pool, hence your code must employ dynamic memory allocation.

When the main thread adds a request to the pool, it signals to the car threads. An idle car thread takes the first available request, while the other threads remain sleeping. Each thread handles a request independently.

A request consists of four parts: source hotel, destination hotel, number of passengers, and travel time. The car thread subtracts the number of people from the source hotel, pauses for a bit, then adds that number to the destination hotel. If there are insufficient number of people at the source hotel, the request must be deferred. The car thread must place the request back in the request pool and try a different request (if any).

Each thread must track the number of passengers it transported and how long it spent travelling (not sleeping). Prior to terminating, display these statistics.

In your code, add a comment block describing how you designed the request pool. Specifically, describe the mechanism(s) you employed to prevent race conditions in global data, and how the main thread notifies car threads when no further requests exist.

Part 3: Data File Format

The data file format is as follows:

Within your Ubuntu VM, use the wget command to fetch the data file http://www.csee.umbc.edu/~jtang/cs421.s16/homework/spring_break.data. The grader will use a different data file during grading. You may not make any assumptions about the number of hotels or requests, other than that there will be at least one of each. Furthermore, you may assume that all requests can be satisfied, though not necessarily in the order presented in the data file.

Part 4: Calculating Travel Times

So as to ensure uniform results, at startup initialize the PRNG using the value given as the final command-line parameter.

When the main thread parses a request line, it needs to determine the actual travel time. Calculate this time as follows:

  1. Subtract the minimum time from the maximum time; call this difference D.
  2. Let R equal to rand() % D.
  3. Let T equal to R plus the minimum time. Store T with the request, when that request is added into the pool.

When a car thread is handling a request, it first subtracts the passengers from the source hotel. Next, the thread sleeps for T milliseconds. Use nanosleep() or usleep() (your choice) to suspend the thread. Then increment the destination hotel by the number of passengers.

Sample Output

Here is a sample output from running the program. This program has added extra debugging output, including which car thread is handling which request.

$ ./hw3 5 spring_break.data 421
Number of hotels: 6
Initial hotel counts:
  Hotel 0: 11
  Hotel 1: 10
  Hotel 2: 15
  Hotel 3: 12
  Hotel 4: 0
  Hotel 5: 7
Thread 1: Taking 6 from hotel 1 to hotel 0 (time 898 ms)
Thread 0: Taking 3 from hotel 2 to hotel 3 (time 184 ms)
Thread 2: Taking 2 from hotel 2 to hotel 1 (time 413 ms)
Thread 3: Taking 6 from hotel 0 to hotel 1 (time 1561 ms)
Thread 4: Taking 7 from hotel 5 to hotel 3 (time 389 ms)
Thread 0: Taking 5 from hotel 2 to hotel 4 (time 353 ms)
Thread 4: Taking 3 from hotel 2 to hotel 5 (time 5176 ms)
Thread 2: Taking 2 from hotel 2 to hotel 1 (time 537 ms)
Thread 0: Taking 15 from hotel 3 to hotel 4 (time 2272 ms)
Thread 1: Taking 6 from hotel 3 to hotel 0 (time 283 ms)
Thread 3 took 6 passengers, for 1561 ms
Thread 0: Taking 6 from hotel 4 to hotel 5 (time 4961 ms)
Thread 2 took 4 passengers, for 950 ms
Thread 1 took 12 passengers, for 1181 ms
Thread 4 took 10 passengers, for 5565 ms
Thread 0 took 29 passengers, for 7770 ms
After all requests:
  Hotel 0: 17
  Hotel 1: 14
  Hotel 2: 0
  Hotel 3: 1
  Hotel 4: 14
  Hotel 5: 9

Other Hints and Notes

Extra Credit

For this assignment, you have the choice of using mutex locks and/or semaphores for thread synchronization. As an added challenge, you may earn an additional 10% on this assignment by using both synchronization techniques.

In hw3.c, implement the code using only mutex locks and/or condition variables. Then create the file hw3-alt.c, that is like hw3.c in all respects, but instead has only semaphores. Then submit both code files.

If you choose to perform this extra credit, put a comment at the top of both files, alerting the grader.