For this exercise you are to write multithreaded C programs that simulate car races.

Part 1

The first program simulates a simple car race. The goal is to determine the winner of the race after all cars have completed the required number of rounds.

The operation of the program should be as follows: The user will run the program and will enter on the command line the number of race cars and the number of laps to go. The program will then create a separate thread for each racecar. As result the program will print out the position of each racecars at the end of each lap.

Example

$formula1 50, 10
Lap 1: 5,7,1,2,9,4,8,3,6,10
Lap 2: 7,5,3,9,4,2,8,1,10,6
Lap 3: 7,5,1,4,3,2,9,8,10,6
Lap 4: 3,5,7,9,4,8,2,1,10,6
...
Lap 50: 2,5,7,1,9,4,8,10,3,6
END

Hints

Each racecar should be implemented as an independent thread.
The different speeds of racecars can be modeled in several ways, for example:
By periodically putting each thread to sleep for a random amount of time.
By periodically advancing each racecar by a random distance.
By periodically calling the yield method.
By using thread priorities.
By a combination of any of these methods above.

Part 2

The second program simulates a car race with accidents. An accident is a random occurrence that involves two racecars. Both racecars involved in an accident are so badly damaged that they can't continue the race and thus do not cross the finish line.

The operation of the program should be as follows: The user will run the program and will enter on the command line the number of race cars, the number of laps to go, and the maximum number of accidents. The program will then create a separate thread for each racecar. As result the program will print the accidents that occurred and the position of the racecars at the end of each lap.

Example:

$formula2 10, 60, 2
Lap 1:
Positions: 5,7,1,2,9,4,8,3,6,10
Lap 2:
Positions: 7,5,3,9,4,2,8,1,10,6
Lap 3:
Accident: (9,4)
Positions: 7,5,1,3,2,8,10,6
Lap 4:
Positions: 3,5,7,8,2,1,10,6
...
Lap 16:
Accident: (1,2)
Positions: 3,5,7,8,10,6
...
Lap 60: 
Positions: 5,7,8,10,3,6
END

Hint

The occurrence of an accident and the cars involved in it can be determined at random.

Part 3

The third program simulates a race with racing teams and pit stops. Each racing team has two or more racecars whose fuel consumption is monitored by the engineers at the pit. Whenever a car is low on fuel the crew chief notifies the driver to come in for a pit stop. Unfortunately, each team has only one refilling station so that only one car can be refueled at each time.

The operation of the program should be as follows: The user will run the program and will enter on the command line the number of teams, the number of race cars per team and the number of laps to go. The program will then create a separate thread for each team and for each racecar. As result the program will print out the positions after each lap and the following events:

Example:

$formula3 5, 4, 60
Lap 1:
Positions: 5,7,1,2,9,4,8,3,6,10
Lap 2:
Positions: 7,5,3,9,4,2,8,1,10,6
Lap 3:
Refueling: 5 
Refueling: 4 
Refueling: 10 
Refueling: 6
No gas: 2
Positions: 7,5,3,9,4,8,1,10,6
Lap 4:
Refueling: 8
Refueling: 9
Refueling: 10
Refueling: 4 
Refueling: 6
No gas: 1
No gas: 9
Positions: 5,7,4,8,3,6,10
...
Lap 50:
Refueling: 10 
Refueling: 8
No gas: 3 
Refueling: 10 
Refueling: 7
Positions: 5,8,7,6,10
END

Part 4

The purpose of this part is to familiarize you with synchronization primitives (synchronized, wait(), notify(), notifyall()) and to train you in solving common synchronization problems (race conditions, mutual exclusion, critical sections, deadlocks etc., see Chap. 8) You are to develop a solution for a slight variation of Part 3. This time, you are asked to use synchronization primitives to make sure that no synchronization errors occur. As a slight change from Part 3, you are asked to develop a solution with the following characteristics:
  1. Racecars that are low on fuel are either refilled immediately (if the station is empty) or line up to be refilled (if the station is occupied by another car). Thus no car will ever run out of fuel.
  2. The decision to refuel or not to refuel is made by each racecar driver individually, not by a racing team.
These changes actually make the problem easier if synchronization is used properly. The following characteristics stay the same: The operation of the program should be as follows: The user will run the program and will enter on the command line the number of teams, the number of race cars per team and the number of laps to go. The program will then create a separate thread for each racecar. As result the program will print out the racecar positions at each lap and the following events:

Example:

$formula4 5 2 60
Lap 1:
Positions: 5,7,1,2,9,4,8,3,6,10
...
Lap 12: 
Car 1 enters station 1
Car 6 enters station 3
Car 2 waits for station 1
Car 1 leaves station 1
Car 2 enters station 1
Car 6 leaves station 3
Car 2 leaves station 1
Positions: 7,5,3,9,4,2,8,1,10,6
...
Lap 60:
Positions: 3,5,7,9,4,8,10,6,4,9
END

General Program Requirements

Each program must satisfy the following requirements:
There is one thread for each racecar.
The winner of a race is determined at random.
If run often enough, each program will eventually simulate every possible race outcome.
Each program runs equally well on cooperative and multithreaded operating systems
No program uses depreciated methods (Thread.stop() etc.)