@@ -859,10 +859,9 @@ public override DateTime Peek() {
859
859
860
860
public class PseudoRealTimeSimulation : ThreadSafeSimulation {
861
861
private const double DefaultRealTimeFactor = 1.0 ;
862
- private const double RealTimeThreshold = 1000.0 ;
863
862
864
- public double RealTimeFactor { get ; private set ; } = DefaultRealTimeFactor ;
865
- public bool IsRunningInRealTime => RealTimeFactor < RealTimeThreshold ;
863
+ public double ? RealTimeFactor { get ; protected set ; } = DefaultRealTimeFactor ;
864
+ public bool IsRunningInRealTime => RealTimeFactor . HasValue ;
866
865
867
866
public PseudoRealTimeSimulation ( ) : this ( new DateTime ( 1970 , 1 , 1 ) ) { }
868
867
public PseudoRealTimeSimulation ( TimeSpan ? defaultStep ) : this ( new DateTime ( 1970 , 1 , 1 ) , defaultStep ) { }
@@ -875,25 +874,43 @@ public override void StopAsync() {
875
874
base . StopAsync ( ) ;
876
875
}
877
876
877
+ protected CancellationTokenSource _delay = null ;
878
+
878
879
public override void Step ( ) {
879
- lock ( _locker ) {
880
- if ( IsRunningInRealTime ) {
881
- var next = ScheduleQ . First . PrimaryPriority ;
882
- var delay = next - Now ;
883
- if ( RealTimeFactor != 1.0 ) delay = TimeSpan . FromMilliseconds ( delay . Milliseconds * 1.0 / RealTimeFactor ) ;
884
- if ( delay > TimeSpan . Zero ) Task . Delay ( delay , _stop . Token ) . Wait ( ) ;
880
+ if ( IsRunningInRealTime ) {
881
+ lock ( _locker ) {
882
+ if ( IsRunningInRealTime ) {
883
+ var next = ScheduleQ . First . PrimaryPriority ;
884
+ var delay = next - Now ;
885
+ if ( RealTimeFactor . Value != 1.0 ) delay = TimeSpan . FromMilliseconds ( delay . Milliseconds / RealTimeFactor . Value ) ;
886
+ if ( delay > TimeSpan . Zero ) {
887
+ _delay = CancellationTokenSource . CreateLinkedTokenSource ( _stop . Token ) ;
888
+ var then = DateTime . UtcNow ;
889
+ Task . Delay ( delay , _delay . Token ) . Wait ( ) ;
890
+ if ( _delay . IsCancellationRequested ) {
891
+ var now = DateTime . UtcNow ;
892
+ var observedDelay = now - then ;
893
+ if ( observedDelay < delay ) {
894
+ Now += observedDelay ;
895
+ return ; // next event is not processed
896
+ }
897
+ }
898
+ }
899
+ }
885
900
}
886
901
}
887
902
base . Step ( ) ;
888
903
}
889
904
890
905
/// <summary>
891
906
/// Switches the simulation to virtual time mode. In this mode, events
892
- /// are processed without delay just like in a ThreadSafeSimulation.
907
+ /// are processed without delay just like in a <see cref=" ThreadSafeSimulation"/> .
893
908
/// </summary>
894
909
public virtual void SwitchToVirtualTime ( ) {
910
+ if ( ! IsRunningInRealTime ) return ;
895
911
lock ( _locker ) {
896
- RealTimeFactor = RealTimeThreshold ;
912
+ RealTimeFactor = null ;
913
+ _delay ? . Cancel ( ) ; // TODO: Same lock region
897
914
}
898
915
}
899
916
@@ -913,12 +930,8 @@ public virtual void SwitchToVirtualTime() {
913
930
/// <param name="realTimeFactor">A factor greater than 0.0 used to scale real time events (higher value = faster execution).</param>
914
931
public virtual void SwitchToRealTime ( double realTimeFactor = DefaultRealTimeFactor ) {
915
932
lock ( _locker ) {
916
- if ( RealTimeFactor <= 0.0 ) throw new ArgumentException ( "The simulation speed scaling factor must not be negative." , nameof ( realTimeFactor ) ) ;
917
- if ( realTimeFactor >= RealTimeThreshold ) {
918
- SwitchToVirtualTime ( ) ;
919
- } else {
920
- RealTimeFactor = realTimeFactor ;
921
- }
933
+ if ( realTimeFactor <= 0.0 ) throw new ArgumentException ( "The simulation speed scaling factor must be strictly positive." , nameof ( realTimeFactor ) ) ;
934
+ RealTimeFactor = realTimeFactor ;
922
935
}
923
936
}
924
937
}
0 commit comments