CMSC 421: Principles of Operating Systems

Homework 3: UnSafeTrack

This homework is due on Tuesday, March 14, at 11:59:59 PM (Eastern daylight 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 16.04 as follows:

  gcc ‐‐std=c99 ‐Wall ‐O2 ‐o hw3 hw3.c ‐pthread
(Note the above is dash, dash, "std=c99", and the other flags likewise are preceded by dashes.) There must not be any compilation warnings in your submission; warnings will result in grading penalties. In addition, your code file 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 a local metropolitan transit agency. On this unfortunate day, the main subway line has shutdown, stranding thousands of passengers. You are responsible for arranging shuttles to take those passengers to their intended destinations. You must transport as many people as possible within the given time frame. You have at your disposable a set number of buses to handle all of the passengers' needs.

Part 1: Starting Up

Your C program must accept a single command-line arguments: the name of a data file. Your program will parse the data file to get the number of subway stations, locations of those subway stations, number of passengers stranded at each station, and their intended destinations. If the user does not give a data file, or if the file does not exist, then display an error message and quit. Otherwise, parse the file as described in Part 3 below.

The data file also contains the number of buses available to you. Your program represents each of these buses as a thread. The program then simulates those buses traveling between stations, picking up and dropping off passengers.

The general flow for your program will be:

  1. Parse the data file.
  2. Initialize all global data values, including all necessary locks.
  3. Spawn a number of threads equal to the number of buses.
  4. For each bus thread, determine where that bus should head next and which passengers will board that bus.
  5. Meanwhile, in the main thread, once per second, display the state of each station.
  6. After a specified time, end the simulation. Each bus thread completes its current route and then terminates itself.
  7. The main thread waits for all bus threads to terminate. It then displays a summary of how many people reached their destination and how many are still stranded.

Part 2: 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.s17/homework/unsafetrack1.data. The grader will use a different data file during grading. You may not make any assumptions about the number of buses, simulation time, or how many passengers are waiting. You can safely assume that you will not have enough time to transport everyone to their destinations.

Part 3: Stations and Buses

There are S stations in your city. Each station's location is described by the coordinates (X, Y), where X and Y are unsigned integers no greater than nine. In this city, the position (0, 0) is the southwest corner, (9, 0) is the southeast corner, and (9, 9) is the northeast corner.

The first coordinate in the data file (i.e., fourth line of the file) corresponds with station 0, the next line is station 1, and so forth up to station S.

After parsing the data file, spawn B threads, each representing a bus. Assign a unique identifier to each thread. Each bus determines which passengers to take. The thread then sleeps, simulating travel time between stations. For simplicity, multiply the Manhattan distance by 250 milliseconds to obtain the sleep time. For example, a trip from a station at (4, 2) to (1, 0) would require 1250 milliseconds. After awakening, the thread drops off all people and then selects a new set of people to take. All B of your buses begin initially at station 0.

If a bus is at an empty station, or if your program wishes to send the bus to a different station with no passengers, the thread must still sleep the requisite time.

Part 4: Passengers

Your buses take groups of people to their destination. A bus's capacity is infinite; it can hold any number of people.

Each group of passengers is described by three numbers. The first number is how many people are in that group. The second number is the station number at which that group is at. The third number is which station the group needs to get to.

Passengers will only ride a bus if it is going directly to their destination. They will not transfer between buses. If, for example, a bus is going to station 4, then only groups with that destination will ride the bus. Also, passengers will not leave their group; a bus must take the entire group of people. A bus may take multiple groups, but only if they all have the same destination station.

Part 5: Main Thread

While your bus threads are busy driving around the virtual city, the main thread continues processing. Once per second, up to T seconds, display the state of all subway stations. For each station, show how many people are still waiting for rides. Afterwards, show how many people have reached their destinations.

After T seconds elapsed, signal to every bus thread to terminate. (How you signal is up to you.) Each bus thread completes its current travel. That thread then displays how many people rode that bus and then terminates itself. Your main thread must wait for all threads to end. Afterwards, display the station status once more.

In your code, add a comment block that answers the following:

  1. While the main thread is displaying the current state of all stations, there is [at least one] potential race condition. Describe a scenario that could trigger that race condition.
  2. How could your program prevent that race condition? No code necessary, just describe what you would do.

Sample Output

Here is a sample output from running the program. This program has added extra debugging output, indicated in italics, to display where each bus is traveling and how many passengers are riding it.

$ ./hw3 unsafetrack1.data
After 0 seconds:
Bus 0: from station 0 to 1, with 6 onboard (travel time = 2000 ms)
Bus 1: from station 0 to 5, with 18 onboard (travel time = 1250 ms)
Bus 3: from station 0 to 4, with 6 onboard (travel time = 1000 ms)
  Station status:
Bus 2: from station 0 to 1, with 0 onboard (travel time = 2000 ms)
Bus 4: from station 0 to 1, with 0 onboard (travel time = 2000 ms)
  0 @ (1, 5): 0 passengers waiting
  1 @ (7, 3): 13 passengers waiting
  2 @ (2, 1): 35 passengers waiting
  3 @ (0, 2): 55 passengers waiting
  4 @ (2, 8): 39 passengers waiting
  5 @ (0, 9): 60 passengers waiting
  0 out of 232 passengers reached their destination
After 1 seconds:
Bus 3: from station 4 to 3, with 8 onboard (travel time = 2000 ms)
  Station status:
  0 @ (1, 5): 0 passengers waiting
  1 @ (7, 3): 13 passengers waiting
  2 @ (2, 1): 35 passengers waiting
  3 @ (0, 2): 55 passengers waiting
  4 @ (2, 8): 31 passengers waiting
  5 @ (0, 9): 60 passengers waiting
  6 out of 232 passengers reached their destination
Bus 1: from station 5 to 2, with 15 onboard (travel time = 2500 ms)
Bus 2: from station 1 to 3, with 3 onboard (travel time = 2000 ms)
Bus 0: from station 1 to 5, with 6 onboard (travel time = 3250 ms)
Bus 4: from station 1 to 2, with 4 onboard (travel time = 1750 ms)
After 2 seconds:
  Station status:
  0 @ (1, 5): 0 passengers waiting
  1 @ (7, 3): 0 passengers waiting
  2 @ (2, 1): 35 passengers waiting
  3 @ (0, 2): 55 passengers waiting
  4 @ (2, 8): 31 passengers waiting
  5 @ (0, 9): 45 passengers waiting
  30 out of 232 passengers reached their destination
Bus 3: from station 3 to 4, with 36 onboard (travel time = 2000 ms)
After 3 seconds:
  Station status:
  0 @ (1, 5): 0 passengers waiting
  1 @ (7, 3): 0 passengers waiting
  2 @ (2, 1): 35 passengers waiting
  3 @ (0, 2): 19 passengers waiting
  4 @ (2, 8): 31 passengers waiting
  5 @ (0, 9): 45 passengers waiting
  38 out of 232 passengers reached their destination
Bus 1: from station 2 to 5, with 8 onboard (travel time = 2500 ms)
Bus 4: from station 2 to 3, with 13 onboard (travel time = 750 ms)
Bus 2: from station 3 to 5, with 6 onboard (travel time = 1750 ms)
Bus 4 carried 17 passengers.
Bus 3 carried 50 passengers.
Bus 0 carried 12 passengers.
Bus 2 carried 9 passengers.
Bus 1 carried 41 passengers.
After 4 seconds:
  Station status:
  0 @ (1, 5): 0 passengers waiting
  1 @ (7, 3): 0 passengers waiting
  2 @ (2, 1): 14 passengers waiting
  3 @ (0, 2): 13 passengers waiting
  4 @ (2, 8): 31 passengers waiting
  5 @ (0, 9): 45 passengers waiting
  129 out of 232 passengers reached their destination

Other Hints and Notes

Extra Credit

In the sample output above, a bus takes the first group of waiting people at the station and any others groups sharing the same destination. If a station is empty, it will deadhead to the next sequentially numbered station. As a friendly competition, and for fame and glory, you may optimize your algorithm. You can earn an additional 10% on this assignment if your program can deliver more people than than the instructor's reference implementation for a different (and larger) data file.

All extra credit submissions will be tested on the same virtual machine. This virtual machine will have more than one CPU allocated to it. Implementations may not cheat, including but not limited to:

The instructor is the final arbitrator of what is considered cheating or not.

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