Лучшее обнаружение тайм-аута для синхронных операций - PullRequest
4 голосов
/ 28 мая 2010

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

static void Main()
{
    bool disposed = false;
    var wait = new ManualResetEvent(false);
    var a = new Action(
        () =>
            {
                Thread.Sleep(1000); // <- some looong action

                if (!disposed)
                    lock (wait)
                        if (!disposed)
                            wait.Set();
            });

    a.BeginInvoke(a.EndInvoke, null);

    bool success = wait.WaitOne(500);
    Console.WriteLine(success ? "success" : "timeout");

    lock (wait)
    {
        wait.Dispose();
        disposed = true;
    }

    Console.ReadLine();
}

выглядит некрасиво. И я знаю, что переменная disposed лямбда-замыкания модифицирована (в отличие от моего ReSharper, мне нравится эта функция C #). Все потому, что я хочу распоряжаться ManualResetEvent. Можете ли вы предложить лучший подход в .NET4? Может, мне просто пропустить удаление события и положиться на GC?

Одно примечание: ManualResetEvent.Set() взрывается, если вы попытаетесь сделать это на удаленном экземпляре.

Ответы [ 2 ]

4 голосов
/ 28 мая 2010

Нет, вы не должны пропускать вызов Dispose и полагаться на GC. Это пустая трата ресурсов, просто и ясно.

В .NET 4.0 я бы взглянул на параллельную библиотеку задач , которая находится в сборке System.Threading, новой для 4.0.

В частности, обратите внимание на класс задач , а также на метод Wait , который позволит вам указать время ожидания.

Кроме того, вы захотите посмотреть, как отменить задание в случае его истечения.

2 голосов
/ 28 мая 2010

Тьфу, теперь, когда я посмотрел немного больше примеров кода с использованием сгенерированного компилятором delegate.BeginInvoke, я вижу, что он возвращает IAsyncResult, что имеет AsyncWaitHandle именно для моей цели:

var a = new Action(() => Thread.Sleep(1000)); // <- some looong action
IAsyncResult asyncResult = a.BeginInvoke(a.EndInvoke, null);
bool success = asyncResult.AsyncWaitHandle.WaitOne(500);

Этот дескриптор ожидания в случае AsyncResult фактически является экземпляром ManualResetEvent, который автоматически удаляется из потока пула потоков сразу после завершения моего асинхронного вызова.

...