Skip to content

Commit ea2d8fb

Browse files
committed
Pull changes from jkarder into branch
1 parent 284e74c commit ea2d8fb

File tree

1 file changed

+30
-17
lines changed

1 file changed

+30
-17
lines changed

src/SimSharp/Core/Environment.cs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,9 @@ public override DateTime Peek() {
859859

860860
public class PseudoRealTimeSimulation : ThreadSafeSimulation {
861861
private const double DefaultRealTimeFactor = 1.0;
862-
private const double RealTimeThreshold = 1000.0;
863862

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;
866865

867866
public PseudoRealTimeSimulation() : this(new DateTime(1970, 1, 1)) { }
868867
public PseudoRealTimeSimulation(TimeSpan? defaultStep) : this(new DateTime(1970, 1, 1), defaultStep) { }
@@ -875,25 +874,43 @@ public override void StopAsync() {
875874
base.StopAsync();
876875
}
877876

877+
protected CancellationTokenSource _delay = null;
878+
878879
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+
}
885900
}
886901
}
887902
base.Step();
888903
}
889904

890905
/// <summary>
891906
/// 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"/>.
893908
/// </summary>
894909
public virtual void SwitchToVirtualTime() {
910+
if (!IsRunningInRealTime) return;
895911
lock (_locker) {
896-
RealTimeFactor = RealTimeThreshold;
912+
RealTimeFactor = null;
913+
_delay?.Cancel(); // TODO: Same lock region
897914
}
898915
}
899916

@@ -913,12 +930,8 @@ public virtual void SwitchToVirtualTime() {
913930
/// <param name="realTimeFactor">A factor greater than 0.0 used to scale real time events (higher value = faster execution).</param>
914931
public virtual void SwitchToRealTime(double realTimeFactor = DefaultRealTimeFactor) {
915932
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;
922935
}
923936
}
924937
}

0 commit comments

Comments
 (0)