2

我有一个 Windows 服务,它在启动时启动一项任务

这个任务有一个 while 循环,在执行一次迭代后它会休眠 5 分钟。

当我停止服务时,首先取消任务,然后执行其他一些操作

如果任务处于睡眠状态,它只会在它醒来时被取消,我希望它被取消,即使它正在睡眠并且不想等待唤醒它。

以下是代码

Task controllerTask = Task.Factory.StartNew(() =>
{
    var interval = 300;
    while(true)
    {
        if (cancellationToken.IsCancellationRequested) 
            break;
        Thread.Sleep(interval * 1000);
        if (cancellationToken.IsCancellationRequested) 
            break;
        //SOME WORK HERE
    }
}, cancellationToken);

有什么办法吗?

编辑:我无法使用 Task.Delay ,我在 System.Threading.Tasks.Task 命名空间中找不到它,因为我使用的是 .Net Framework 4.0 而不是 4.5

有没有其他更好的解决方案适用于 4.0。

4

4 回答 4

11

使用Task.Delay而不是Thread.Sleep. 它需要一个CancellationToken参数,因此您可以在延迟结束之前中止它。

如果你使用的是异步代码,你可以这样写:

await Task.Delay(duration, cancellationToken);

如果是同步代码,你可以等待任务:

Task.Delay(duration, cancellationToken).Wait();
于 2013-07-11T15:40:03.270 回答
2

受其他答案的启发,使用 await 解决此问题的简单示例:

public static class TaskExtension
{
    /// <summary>
    /// Call to highlight fact that you do not want to wait on this task.
    ///
    /// This nicely removes resharper warnings without need for comments.
    /// </summary>
    /// <param name="task"></param>
    public static void FireAndForget(this Task task)
    {
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var cancellationToken = new CancellationTokenSource();
        TaskCode(cancellationToken.Token).FireAndForget();
        Console.ReadLine();
        cancellationToken.Cancel();
        Console.WriteLine("End");
        Console.ReadLine();
    }

    private static async Task TaskCode(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            var interval = TimeSpan.FromSeconds(1);
            await Task.Delay(interval, cancellationToken);

            //SOME WORK HERE
            Console.WriteLine("Tick");
        }
    }
}
于 2013-07-11T16:05:46.460 回答
2

这是您可以在 C# 4.0 VS2010 中使用的一种阻塞解决方案。

cancellationToken.WaitHandle.WaitOne(TimeSpan.FromMinutes(5));

当您取消令牌源或超时(这是您想要的睡眠间隔)时,它将解除阻塞。

于 2013-07-12T08:42:56.920 回答
0

我已经将长时间睡眠分解为多个小睡眠,以下是修改后的代码:

Task controllerTask = Task.Factory.StartNew(() =>
{
 while(true)
 {
     if (cancellationToken.IsCancellationRequested) break;
     var sleepTime = 10;
     if (interval < sleepTime)
         interval = sleepTime;

     var iteration = (interval / sleepTime);
     if ((interval % sleepTime) > 0)
         iteration++;
     bool cancel = false;
     for (int i = 0; i < iteration; i++)
     {
         Thread.Sleep(sleepTime * 1000);
         if (cancellationToken.IsCancellationRequested) { cancel = true; break; };
     }
     if (cancel) break;

     //SOME WORK HERE
 }
}
于 2013-07-11T15:34:27.607 回答