Windows服务任务-轮询取消

时间:2019-03-21 12:17:35

标签: c# .net windows-services polling cancellation-token

我正在编写Windows服务,并发现了一个示例,该示例建议如下编写轮询Windows服务:

private void Poll()
{
    CancellationToken cancellationPoll = ctsPoll.Token;
    while (!cancellationPoll.WaitHandle.WaitOne(tsInterval))
    {
        PollDatabase();
        // Occasionally check the cancellation state.
        if (cancellationPoll.IsCancellationRequested)
        {
            break;
        }
    }
}

在取消方面,如果我同时需要cancelPoll.WaitHandle.WaitOne()和cancelPoll.IsCancellationRequested,还是有些事情,他们只需要一个就可以了吗?

3 个答案:

答案 0 :(得分:1)

!cancellationPoll.WaitHandle.WaitOne(tsInterval)可以确保轮询间隔,因此两次轮询之间至少要有tsIntetval(加上操作时间):

--tsInterval--|--operation--|--tsInterval--|...

如果您查看CancellationToken.WaitHandle的文档,则会显示以下内容:

  

取消令牌时发出的WaitHandle信号。

因此,在您的情况下,操作cancellationPoll.IsCancellationRequested就足够了,因为它后面没有任何内容。但是想象一下这样的情况:

while (!cancellationPoll.WaitHandle.WaitOne(tsInterval))
{
    //long operation A

    if (cancellationPoll.IsCancellationRequested)
    {
        break;
    }

    //long operation B

    if (cancellationPoll.IsCancellationRequested)
    {
        break;
    }
    //long operation C
}

在这种情况下,偶尔检查取消状态以避免长时间运行很有意义...

答案 1 :(得分:-1)

需要!cancellationPoll.WaitHandle.WaitOne(tsInterval),以便您不必一直等待。 WaitOne(tsInterval)将返回,因为令牌取消了单个信号以使其取消或时间已用完。如果令牌收到取消信号WaitOne(tsInterval),则会返回true,从而结束循环。

例如,如果您要执行以下操作:

while(true)
{
    // long operation
    if (cancellationPoll.IsCancellationRequested)
    {
        break;
    }

    Thread.Sleep(tsInterval);
}

如果在线程被Thread.Sleep()阻塞的同时请求取消,则整个操作将不知道直到Thread.Sleep()完成并且下一个循环运行到{ {1}}语句。

答案 2 :(得分:-1)

WaitHanlde的等待在这里是多余的,因为从结果的角度来看,它的作用与IsCancellationRequested相同-表示请求取消(但执行方式略有不同)。因此,对于您的情况,您可以选择一种方法:WaitHandleIsCancellationRequested。但是请记住,WaitHandleIDisposable,需要处理相关的CancellationTokenSource。如果您选择使用IsCancellationRequested,请不要忘记添加一个调用,该调用应该重新安排诸如Thread.Sleep之类的线程,以免过度利用CPU资源。 可以应用WaitHanlde的情况之一是当您需要等待句柄并且想要向这种等待引入取消语义时:

 WaitHandle.WaitAny(new [] { handleToWait, cancellationHandle });