/// <summary> /// This is the thread that will cause the car to move forward forever /// until it finishes its trip or crashes. /// </summary> /// <param name="ThreadParameter">Any parameter that the thread needs</param> protected void Go(object ThreadParameter) { if (ThreadParameter is Wind windy) { string ThreadTypeInfo = ""; switch (windy.Model) { case ThreadingModel.ManualThreads: { ThreadTypeInfo = $"Using new ParameterizedThreadStart thread {Thread.CurrentThread.ManagedThreadId}."; } break; case ThreadingModel.ThreadPoolThreads: { ThreadTypeInfo = $"Using ThreadPool thread {Thread.CurrentThread.ManagedThreadId}."; } break; case ThreadingModel.TaskThreads: { ThreadTypeInfo = $"Using TaskThreads thread {Thread.CurrentThread.ManagedThreadId}."; } break; } Console.WriteLine($"Started to drive car {CarId}, travelling in the {Direction.ToString()} direction, enter intersection every {MilesTillIntersection} miles.\r\nThe wind is coming out of the {windy.WindDirection.ToString()} at {windy.Speed} MPH.{ThreadTypeInfo}"); } // Signal that this thread has started. We don't want to let // the cars start the race until ALL cars have started their // thread and are ready to go. CarIsReadyToGo.Set(); // If the caller wants ALL cars to start at the same time // then all threads will block on the ManualResetEvent. // When "Set" is called, ALL threads/cars will start/unblock // at the same time StartAllCars.WaitOne(); while ((MilesTravelled < MilesLengthOfTrip) && !CarCrashed) { MoveOneStep(); } if (CarCrashed) { Console.WriteLine($"Vehicle {CarId} CRASHED in the intersection after {MilesTravelled} miles of a {MilesLengthOfTrip} mile trip"); } else { Console.WriteLine($"Vehicle {CarId} successfully completed the {MilesLengthOfTrip} mile trip"); // Create BOGUS event to have this car removed from list of all cars // because it has completed the trip. TripCompleted = true; CarEnteredOrExitedIntersectionEvent?.Invoke(this); } }
/// <summary> /// Move the car forward one step and tell event listener when the car entered or exited the intersection /// </summary> protected void MoveOneStep() { ++MilesTravelled; Thread.Sleep(MovementSleep); // Check if this car needs a pit stop if ((MilesTravelled % MilesTillPitStop) == 0) { // Try to enter pit area. If there is a spot available // then the car can enter, otherwise it MUST wait for // one of the cars already in the pit area to get out. PitStop.WaitOne(); // Count the number of times the car has entered the pit area during the race. ++NumberOfPitStopMade; // Spend some time in the pit area Thread.Sleep(MovementSleep); // Leave the pit area to allow other cars to enter PitStop.Release(); } // Check if we are in intersection if ((MilesTravelled % MilesTillIntersection) == 0) { // Wait at stop sign before entering the intersection if (WaitAtStopSign) { StopSign.WaitOne(); } InIntersection = true; // Indiate this car entered the intersection CarEnteredOrExitedIntersectionEvent?.Invoke(this); // If the car crashed, then it was already removed from the intersection if (!CarCrashed) { // Car spends some time in the intersection Thread.Sleep(MovementSleep); InIntersection = false; // Indiate this car left the intersection CarEnteredOrExitedIntersectionEvent?.Invoke(this); } // Tell any other car waiting at the stop sign // that we exited the intersection and it's ok for them // to enter. if (WaitAtStopSign) { StopSign.Set(); } } }