Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
395 views
in Technique[技术] by (71.8m points)

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

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 is much more complex, and has heavy recursion and is spread over many classes, but this should give a general idea of how it works. Basically any time something calls recursion or performs something that might take time, it calls AssertTimeout().

private DateTime endTime;
public void PerpareTimeout(int timeoutMilliseconds)
{
    endTime = DateTime.UtcNow.AddMilliseconds(timeoutMilliseconds);
}

public void AssertTimeout()
{
    if (DateTime.UtcNow > endTime)
        throw new TimeoutException();
}

public void DoWork1()
{
    foreach (var item in workItems)
    {
        AssertTimeout();
        DoWork2(item)
    }
}
public void DoWork2(WorkItem item)
{
    foreach (var item in workItems)
    {
        AssertTimeout();
        // ...
    }
}

So the problem comes in when I have a debugger attached and I pause execution. I want to somehow disable the timeout for the amount of time paused. So if it runs for 2 seconds, I hit a breakpoint and wait 5 minutes, and then resume, it will run 3 more seconds after resuming execution before timing out.

I could use something like this:

public void PrepareTimeout(int timeoutMilliseconds)
{
    if (System.Diagnostics.Debugger.IsDebuggerAttached)
        endTime = DateTime.MaxValue;
    else
        endTime = DateTime.UtcNow.AddMilliseconds(timeoutMilliseconds);
}

But that's basically giving an infinite timeout whenever the program is running in a debug environment, and I want it to time out normally if I don't pause it.

Is there any way to measure time elapsed without counting the time spent paused by the debugger?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...