Реализация тайм-аута RegEx в .NET 4 - PullRequest
7 голосов
/ 27 февраля 2012

Платформа: Silverlight 4, .NET 4

С предварительным просмотром .NET 4.5 Developer был улучшен класс RegEx , позволяющий установить значение Timeout, которое помешало бы движку RegExвывешивание пользовательского интерфейса при возникновении проблем с сопоставлением с шаблоном.

Запрос предложений по реализации аналогичной функциональности в приложении .NET 4 Silverlight.

Заранее спасибо.

Ответы [ 4 ]

11 голосов
/ 27 февраля 2012

Общий пример:

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();
}

Использование:

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

Обновление:

Как указывает Christian.K, асинхронный поток все еще будет продолжать работать.

Вот тот, где поток закончится:

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

Обновление:

Исправлено над фрагментом, чтобы корректно обрабатывать исключения.

3 голосов
/ 27 февраля 2012

Это не так просто - но это можно сделать, используя два потока: первый выполняет регулярное выражение, а второй - первый поток, если он выполняется слишком долго. Это само по себе проблематично.

2 голосов
/ 06 июня 2012

Я заново реализовал приведенный выше код, изменив его так, чтобы я считал его более надежным.

    /// <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!
        } 
1 голос
/ 27 февраля 2012

Стандартный способ получить тайм-аут для чего-то, что еще не входит в эту функцию, - это просто запустить все, что вы хотите обработать в отдельном потоке, а затем в вашем основном потоке вы используете Thread.Join с соответствующий тайм-аут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...