protected virtual void Dry(CancellationTokenPair pair) { byte unitsToRemove; { using var lls = LaundryFlags.SpinLock(TimeSpan.FromSeconds(2)); unitsToRemove = lls.LoadedLaundryItem != LaundryItems.InvalidItem ? lls.LoadedLaundryItem.Dampness : throw new StateLogicErrorException( "It should not be possible to lack laundry during the wash cycle."); } byte unitsToDeduct = unitsToRemove; TimeSpan timeRequired = TimeToDecrementDampnessPerUnit * unitsToRemove; double randomFactor = RandomNumberSource.Next(1, 11) / 100.0; //introduce randomness factor of 10%, either direction Debug.Assert(randomFactor >= 0.0 && randomFactor <= 0.11); TimeSpan randomTimeToAddOrSub = timeRequired * randomFactor; Debug.Assert(randomTimeToAddOrSub <= timeRequired); bool negate = RandomNumberSource.Next(1, 3) == 1; randomTimeToAddOrSub = negate ? -randomTimeToAddOrSub : +randomTimeToAddOrSub; timeRequired += randomTimeToAddOrSub; Stopwatch sw = null; try { sw = HighPrecisionTimer; sw.Restart(); SimulateWait(pair, timeRequired); } catch (OperationCanceledException) { if (sw == null) { string log = "For some reason the stopwatch is null."; TerminationHelper.TerminateApplication(log); return; } TimeSpan elapsed = sw.Elapsed; double percentage = elapsed >= timeRequired ? 1.0 : elapsed / timeRequired; unitsToDeduct = Convert.ToByte(Math.Floor(unitsToRemove * percentage)); throw; } finally { sw?.Reset(); byte newSetting = (byte)(unitsToRemove - unitsToDeduct); Debug.Assert(newSetting <= unitsToRemove); using var lls = LaundryFlags.SpinLock(TimeSpan.FromSeconds(2)); lls.SetDampFactor(newSetting); Debug.Assert(lls.LoadedLaundryItem.Dampness <= unitsToRemove); } }
protected virtual void Soak(CancellationTokenPair token) { Stopwatch sw = null; try { Debug.WriteLine("Beginning Cleanse Soak"); byte oldDampness; byte newDampness; sw = HighPrecisionTimer; sw.Reset(); sw.Start(); { using LockedLaundryStatus lls = LaundryFlags.SpinLock(token.IndividualToken, TimeSpan.FromSeconds(2)); var res = lls.SoakLaundry() ?? throw new StateLogicErrorException( "It is supposed to be impossible to start the machine without laundry in it."); oldDampness = res.OldDampness; newDampness = res.NewDampness; } Debug.Assert(newDampness >= oldDampness); int dampnessUnitsIncrease = newDampness - oldDampness; TimeSpan totalTimeRequired = TimeToIncrementDampnessPerUnit * dampnessUnitsIncrease; TimeSpan timeRemaining = totalTimeRequired - sw.Elapsed; if (timeRemaining > TimeSpan.Zero) { SimulateWait(token, timeRemaining, "Beginning soak wait", "Ending soak wait"); } } catch (StateLogicErrorException ex) { Console.Error.WriteLineAsync(ex.ToString()); Environment.Exit(-1); } catch (TimeoutException) { Console.Error.WriteAsync( $"Unable to obtain lock in {nameof(Soak)} method of {nameof(WashTask)} task."); throw; } finally { sw?.Reset(); Debug.WriteLine("Ending soak."); } }
protected virtual void Cleanse(CancellationTokenPair token) { byte unitsToRemove; { using var lls = LaundryFlags.SpinLock(TimeSpan.FromSeconds(2)); unitsToRemove = lls.LoadedLaundryItem != LaundryItems.InvalidItem ? lls.LoadedLaundryItem.SoiledFactor : throw new StateLogicErrorException( "It should not be possible to lack laundry during the wash cycle."); } byte unitsToDeduct = unitsToRemove; TimeSpan timeRequired = TimeToRemoveOneUnitOfSoil * unitsToRemove; Stopwatch sw = null; try { sw = HighPrecisionTimer; sw.Restart(); if (timeRequired > TimeSpan.Zero) { SimulateWait(token, timeRequired, "Beginning cleanse wait."); } } catch (IndividualOperationCancelledException) { if (sw == null) { string log = "For some reason the stopwatch is null."; TerminationHelper.TerminateApplication(log); return; } TimeSpan elapsed = sw.Elapsed; double percentage = elapsed >= timeRequired ? 1.0 : elapsed / timeRequired; unitsToDeduct = Convert.ToByte(Math.Floor(unitsToRemove * percentage)); throw; } finally { sw?.Reset(); byte newSetting = (byte)(unitsToRemove - unitsToDeduct); Debug.Assert(newSetting <= unitsToRemove); using var lls = LaundryFlags.SpinLock(TimeSpan.FromSeconds(2)); lls.SetSoilFactor(newSetting); Debug.Assert(lls.LoadedLaundryItem.SoiledFactor <= unitsToRemove); } }