2

起動時にタスクを開始する Windows サービスがあります

このタスクには while ループがあり、1 回の反復を実行した後、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 を使用できません。4.5 ではなく .Net Framework 4.0 を使用しているため、 System.Threading.Tasks.Task namespace で見つけることができません。

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 で使用できるブロック ソリューションの 1 つです。

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 に答える