ThreadPool.RegisterWaitForSingleObject(CancellationToken.WaitHandle):它会完成吗?

时间:2013-10-14 23:24:47

标签: c# .net asynchronous cancellation cancellation-token

我正在根据question上接受的答案实施代码。现在我遇到一个问题,看起来线程处于打开状态:应用程序永远不会完成。

我认为这可能是由于下面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;
}

1 个答案:

答案 0 :(得分:2)

是的,线程池将等待取消令牌的等待句柄无限期地发出信号。

您需要保存RegisterWaitForSingleObject()的返回值才能取消未完成的等待操作。请参阅ThreadPool.RegisterWaitForSingleObject备注部分,因为它表明您应始终取消注册等待。

优秀的等待操作不应该使你的过程保持活跃。