ThreadPool.RegisterWaitForSingleObject(CancellationToken.WaitHandle): он когда-нибудь завершится?

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

Я думаю, что это может быть вызвано нижним из двух вхождений ThreadPool.RegisterWaitForSingleObject ниже. Первый прослушивает завершение WebRequest или истечение времени ожидания. Второй прослушивает запрашиваемую отмену. Теперь мне интересно: второй когда-нибудь закончится, если не будет запрошена отмена, или он будет ждать вечно?

public static Task<WebResponse> GetResponseAsync(this WebRequest request, CancellationToken token)
{
    if (request == null)
        throw new ArgumentNullException("request");

    bool timeout = false;
    TaskCompletionSource<WebResponse> completionSource = new TaskCompletionSource<WebResponse>();

    AsyncCallback completedCallback =
        result =>
        {
            try
            {
                completionSource.TrySetResult(request.EndGetResponse(result));
            }
            catch (WebException ex)
            {
                if (timeout)
                    completionSource.TrySetException(new WebException("No response was received during the time-out period for a request.", WebExceptionStatus.Timeout));
                else if (token.IsCancellationRequested)
                    completionSource.TrySetCanceled();
                else
                    completionSource.TrySetException(ex);
            }
            catch (Exception ex)
            {
                completionSource.TrySetException(ex);
            }
        };

    IAsyncResult asyncResult = request.BeginGetResponse(completedCallback, null);
    if (!asyncResult.IsCompleted)
    {
        if (request.Timeout != Timeout.Infinite)
        {
            WaitOrTimerCallback timedOutCallback =
                (object state, bool timedOut) =>
                {
                    if (timedOut)
                    {
                        timeout = true;
                        request.Abort();
                    }
                };

            ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, timedOutCallback, null, request.Timeout, true);
        }

        if (token != CancellationToken.None)
        {
            WaitOrTimerCallback cancelledCallback =
                (object state, bool timedOut) =>
                {
                    if (token.IsCancellationRequested)
                        request.Abort();
                };

            ThreadPool.RegisterWaitForSingleObject(token.WaitHandle, cancelledCallback, null, Timeout.Infinite, true);
        }
    }

    return completionSource.Task;
}

person Johan van der Slikke    schedule 14.10.2013    source источник


Ответы (1)


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

Вам необходимо сохранить возвращаемое значение RegisterWaitForSingleObject(), чтобы отменить невыполненную операцию ожидания. См. раздел ThreadPool.RegisterWaitForSingleObject, поскольку в нем указано, что вы всегда должны отменять регистрацию ожиданий.

Однако незавершенная операция ожидания не должна поддерживать ваш процесс в рабочем состоянии.

person William    schedule 15.10.2013
comment
Спасибо, это помогло мне решить проблему. На самом деле это поддерживало процесс. Возможно, потому что я использую Mono. - person Johan van der Slikke; 16.10.2013