8

Platform: Silverlight 4, .NET 4

With the .NET 4.5 Developer preview the RegEx class has been enhanced to allow setting of a Timeout value which would prevent the RegEx engine from hanging the UI if there are issues with the pattern matching.

Requesting suggestions to implement a similar functionality in a .NET 4 Silverlight application.

Thanks in advance.

1

4 Answers 4

13

Generic example:

public static R WithTimeout<R>(Func<R> proc, int duration)
{
  var wh = proc.BeginInvoke(null, null);

  if (wh.AsyncWaitHandle.WaitOne(duration))
  {
    return proc.EndInvoke(wh);
  }

  throw new TimeOutException();
}

Usage:

var r = WithTimeout(() => regex.Match(foo), 1000);

Update:

As pointed out by Christian.K, the async thread will still continue running.

Here is one where the thread will terminate:

public static R WithTimeout<R>(Func<R> proc, int duration)
{
  var reset = new AutoResetEvent(false);
  var r = default(R);
  Exception ex = null;

  var t = new Thread(() =>
  {
    try
    {
      r = proc();
    }
    catch (Exception e)
    {
      ex = e;
    }
    reset.Set();
  });

  t.Start();

  // not sure if this is really needed in general
  while (t.ThreadState != ThreadState.Running)
  {
    Thread.Sleep(0);
  }

  if (!reset.WaitOne(duration))
  {
    t.Abort();
    throw new TimeoutException();
  }

  if (ex != null)
  {
    throw ex;
  }

  return r;
}

Update:

Fixed above snippet to deal with exceptions correctly.

Sign up to request clarification or add additional context in comments.

8 Comments

But won't this (also) continue running in the background if a timeout occurs?
@Christian.K: I thought so, but it seems you are correct! Thanks :) Back to drawing board for this one!
Nicely done. A couple notes about this though. Calling t.Abort() in your example will cause a MethodAccessException as explained here... msdn.microsoft.com/en-us/library/ty8d3wta(v=vs.95).aspx The only case when it won't is when it's a Silverlight 5 application running with elevated trust as explained here... msdn.microsoft.com/en-us/library/ee721083(v=vs.95).aspx I was hoping that this would also work with Silverlight 4 in elevated trust, but it appears that it doesn't. I get the same exception I do in partial trust.
@SteveWortham: Thanks for that helpful information :) So I guess there is no way to abort a thread in Silverlight under partial trust? Seems counter-intuitive.
Nope. There's no way I'm aware of. Your code should work for Silverlight 5 elevated-trust though. For this particular example, it's like we need .NET 4.5's Regex class compiled for Silverlight so we gain access to the Timeout property.
|
3

It is not that simple - but it can be done using two threads with the first doing the regex, the second killing the first thread if itruns too long. This is problematic in itself, though.

2 Comments

+1 for acknowledging "This is problematic in itself, though". :-)
Sadly it is the only w o do that without the regex method supporting it ;( It is a very good thing to have, though, but... well... .NET 4.5 here I come... this week.
2

I re-implemented the above code changing it in a way that I belive is more reliable.

    /// <summary>
    /// Executes function proc on a separate thread respecting the given timeout value.
    /// </summary>
    /// <typeparam name="R"></typeparam>
    /// <param name="proc">The function to execute.</param>
    /// <param name="timeout">The timeout duration.</param>
    /// <returns></returns>
    public static R ExecuteWithTimeout<R>(Func<R> proc, TimeSpan timeout) {
        var r = default(R); // init default return value
        Exception ex = null; // records inter-thread exception

        // define a thread to wrap 'proc'
        var t = new Thread(() => {
            try {
                r = proc();
                }
            catch (Exception e) {
                // this can get set to ThreadAbortException
                ex = e;

                Debug.WriteLine("Exception hit");

                }
            });

        t.Start(); // start running 'proc' thread wrapper
        // from docs: "The Start method does not return until the new thread has started running."

        if (t.Join(timeout) == false) {
            t.Abort(); // die evil thread!
            // Abort raises the ThreadAbortException
            int i = 0;
            while ((t.Join(1) == false) && (i < 20)) { // 20 ms wait possible here
                i++;
                }
            if (i >= 20) {
                // we didn't abort, might want to log this or take some other action
                // this can happen if you are doing something indefinitely hinky in a
                // finally block (cause the finally be will executed before the Abort 
                // completes.
                Debug.WriteLine("Abort didn't work as expected");
                }
            }

        if (ex != null) {
            throw ex; // oops
            }
        return r; // ah!
        } 

Comments

1

The standard way to get a timeout on something that doesn't already come with the feature, is to simply start whatever you want to process on a separate thread, and then in your main thread, you use Thread.Join with the appropriate timeout.

3 Comments

But keep in mind that the other thread does not stop running, just because your join-timeout expired. If one can live with that, fine. However, depending on the frequency regex threads my be started (impatient user clicking a link/button), that may lead to a whole bunch of running threads and used resources. Not to speak of run-away regexes "burning" CPU in the background.
Obviously, if you don't want it to continue, then you add a Thread.Abort after the timeout... But in some cases you might just want to pop up a warning on the GUI saying "This is taking longer than expected"
Yes, but that "obvious" part is what the new Regex-timeout support in .NET 4.5 does - and the hard one (Thread.Abort has it's own set of issues).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.