我有一个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。
答案 0 :(得分:11)
使用Task.Delay
代替Thread.Sleep
。它需要CancellationToken
参数,因此您可以在延迟结束之前中止它。
如果您使用的是异步代码,可以这样写:
await Task.Delay(duration, cancellationToken);
如果是同步代码,您可以等待任务:
Task.Delay(duration, cancellationToken).Wait();
答案 1 :(得分:2)
受到其他答案的启发,使用等待此问题的简单示例:
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");
}
}
}
答案 2 :(得分:2)
这是一个可以在C#4.0,VS2010中使用的阻止解决方案。
cancellationToken.WaitHandle.WaitOne(TimeSpan.FromMinutes(5));
取消令牌源或超时时,它将取消阻止,这是您所需的睡眠间隔。
答案 3 :(得分: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
}
}