How to ignore the passage of time while debugger has code paused?

后端 未结 3 604
时光取名叫无心
时光取名叫无心 2020-12-20 00:39

I have calculations I\'m performing which I need to timeout if it runs too long. I might set a timeout of 5 seconds, and do periodic polls throughout my code. Actual code

相关标签:
3条回答
  • 2020-12-20 01:11

    Ideally you would want some events to be fired when the code is paused. Since the Debugger doesn't fire an event then a workaround is needed as mentioned by Matias.

    His solution requires that you know the exact point at which you should start/stop a Stopwatch and I will build on that. The downside to this solution is that it requires constant polling at a high enough resolution for your needs (which could be detrimental to the rest of your application running thereby affecting whatever numbers you are trying to retrieve out of the timer).

    The ultimate aim is that we will do the calculation:

    "Running time paused" = "Total time taken" - "Total time paused"

    We will try to keep track of when the last time the program was actively running, and then find out when the program next actively runs after it resumes from debug.

    public static class ProgramTimer
    {
        public static int resolution = 1000; //resolution of time needed in ms
        private static System.Diagnostics.Stopwatch stopwatch;
        private static System.Timers.Timer pollingTimer;
        private static System.TimeSpan lastMeasuredDebugTimespan;
    
        public static void Start()
        {
            pollingTimer = new System.Timers.Timer();
            pollingTimer.Interval = resolution;
            pollingTimer.Elapsed += timerEvent;
        }
    
        private static void timerEvent()
        {
            if (System.Diagnostics.Debugger.IsDebuggerAttached) {
                if (stopwatch == null) {
                    stopwatch = System.Diagnostics.Stopwatch.StartNew();
                }
            } else {
                if (stopwatch != null) {
                    stopwatch.Stop();
                    lastMeasuredDebugTime = stopwatch.Elapsed.TotalMilliseconds;
                    stopwatch = null;
                }
            }
        }
    
        public static System.TimeSpan getTimespanInDebug()
        {
            if (lastMeasuredDebugTimespan) {
                return lastMeasuredDebugTimespan;
            }
            return null;
        }
    }
    

    In PrepareTimeout you would call: ProgramTimer.Start()

    And in AssertTimeout:

    public void AssertTimeout()
    {
        DateTime newEndTime;
        newEndTime = endTime; 
        if (ProgramTimer.getTimespanInDebug()) {
            newEndTime = endTime.Subtract(ProgramTimer.getTimespanInDebug());
        }
        if (DateTime.UtcNow > newEndTime)
            throw new TimeoutException();
    }
    

    Hope that helps!

    0 讨论(0)
  • 2020-12-20 01:13

    There is a not so nice workaround.

    You have to use Stopwatch instead of calculating the difference between present time and start time.

    Let's say you have the following piece of code:

    Stopwatch watch = Stopwatch.StartNew();
    
    DoSomething();
    DoAnotherThing(); <-- You want to add a breakpoint here
    DoFinalThings();
    
    watch.Stop();
    

    You can achieve what you want adding three lines of code before the line you want to breakpoint:

    Stopwatch watch = Stopwatch.StartNew();
    
    DoSomething();
    
    watch.Stop();       // Stops measuring time
    Debugger.Break();   // Programatically breaks the program at this point
    watch.Start();      // Resumes measuring time
    
    DoAnotherThing();
    DoFinalThings();
    
    watch.Stop();
    
    0 讨论(0)
  • 2020-12-20 01:20

    After seeing Matias Cicero's answer, I had an idea:

    If debugger is attached, start a watchdog thread which does nothing but sleep. Maybe in 100 millisecond increments. If the program becomes paused, the call to Thread.Sleep will take longer than expected, and it can increment the end time by the difference.

    public class DebugWatchDog : IDisposable
    {
        private bool Terminated;
        private Action<DateTime> updateEndTime;
        private DateTime endTime;
        public DebugWatchDog(Action<DateTime> updateEndTime, DateTime endTime)
        {
            if (!System.Diagnostics.Debugger.IsDebuggerAttached)
                return;
            this.updateEndTime = updateEndTime;
            this.endTime = endTime;
            updateEndTime(DateTime.MaxValue);
            var thread = new Thread(Watch);
            thread.Start();
        }
        public void Dispose()
        {
            lock (this)
                Terminated = true;
        }
        private void Watch()
        {
            DateTime priorTime = DateTime.UtcNow;
            while (true)
            {
                lock (this)
                    if (Terminated)
                        return;
                Thread.Sleep(100);
                DateTime nextTime = DateTime.UtcNow;
                var diff = nextTime - priorTime;
                if (diff.TotalMilliseconds > 115)
                {
                    endTime += diff;
                }
                if (DateTime.UtcNow > endTime)
                {
                    updateEndTime(endTime);
                    return;
                }
                priorTime = nextTime;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题