0

待機時間の経過後にSQL問合せを実行しているタスクのリストを取り消す必要があります。 CancellationTokenを実装してタスクをキャンセルすることができます。しかし、取り消しは協調的なものなので、すべてのステップの前に自分のアクション内で取り消しトークンのステータスを確認する必要があります。しかし、私の場合、SQLクエリは長い時間がかかりますが、クエリの実行前後にキャンセルトークンの状態を確認することしかできません。後のケースでは役に立たないので、キャンセルトークンのステータスに基づいてこれらのタスクの中でクエリの実行をキャンセルするにはどうすればよいですか?C#長時間実行されているSQL問合せを実行中のタスクのリストを取り消します。

public void EnqueueTask(Action action, CancellationToken cancelToken = default(CancellationToken)) 
{ 
    var task = new Task(action, cancelToken, TaskCreationOptions.LongRunning); 
    if (_workTaskQueue.TryAdd(task)) 
    { 
     TaskHandler?.Invoke 
      (new TaskProcessingArguments 
      { 
       ISTaskAdded = true, 
       Message = "Task Added to Queue", 
       PendingTaskCount = _workTaskQueue.Count, 
      }); 
    } 
    else 
    { 
     TaskHandler?.Invoke 
      (new TaskProcessingArguments 
      { 
       ISTaskAdded = false, 
       Message = "Timedout while adding Task to Queue", 
       PendingTaskCount = _workTaskQueue.Count, 
      }); 
    } 
} 

public void DequeueTask(int maxConcurrency, CancellationToken ct) 
{ 
    var tasks = new List<Task>(); 
    using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) 
    { 
     foreach (var task in _workTaskQueue.GetConsumingEnumerable()) 
     { 
      try 
      { 
       if (!(task.IsCanceled) && task.Status == TaskStatus.Created) 
       { 
        tasks.Add(task); 
        task.Start(); 
       } 
      } 
      finally { 
       concurrencySemaphore.Release(); 
      } 
     } 
    } 
    Task.WaitAll(tasks.ToArray()); 
} 

    void StartWorker() 
    { 
     Task.Factory.StartNew(() => 
     { 
      try 
      { 
       taskQueue.DequeueTask(maxConcurrency, cancellationToken); 
      } 
      finally { 
       lock (syncObj) 
       { 
        IsCompleted = true; 
       } 
       //Logger.Info("Closing Worker task!!!"); 
      } 
     }, TaskCreationOptions.LongRunning); 
    } 
+2

、何をquerysを実行するために使用しますか? cancelTokenをパラメータとしてasyncメソッドに渡すことが可能な場合もあります。 覚えていること:特定の時間の後にSQLクエリをキャンセルすると、クエリが実行された場所(およびキャンセルトークンではない)にタイムアウト(ミリ秒)を渡す方がよいでしょう。あなたが知っていない場合にのみ、cancelationtokenを使用します。停止する場合(例:ユーザーが停止したい場合) – maerlin

+0

Maerlin、サンプルコードを追加しました。私はすでにSQLクエリのための個々のタイムアウトを持っていますが、私はセマフォを使用して小さなバッチでタスクを実行しているので、10秒後にバッチタイムアウトの各クエリと10バッチがあり、100秒10秒後にすべてのタスクの実行をキャンセルしたいと考えています。 – Nitheesh

+0

非同期操作 –

答えて

2

あなたはEnqueueTask方法にアクションインスタンスとして渡された関数の内部でCancellationTokenを使用する必要があります。

など。次のコードは、コマンドCancellationTokenは、SQLの実行を終了するために使用することができます方法を示しています。それはあなたのコードに依存し

using (SqlConnection conn = new SqlConnection(sqlConnection)) 
    { 
     conn.Open(); 
     var cmd = conn.CreateCommand(); 

     using (cancellationToken.Register(() => cmd.Cancel())) 
     { 
      cmd.CommandText = sql; 
      cmd.ExecuteNonQuery(); 
     } 
    } 
+0

'ExecuteNonQuery'の直後に閉じるcancellationToken.Registerの周りにブロックを置くことになります。 – Tim

+0

ありがとう@Timが修正されました。 –

+0

パーフェクト!これは私の問題を解決しました。ありがとうございました。 – Nitheesh

0

新しいスレッドを使用してクエリを起動するタスクを作成すると、タスクは引き続きCancelationTokenのステータスをチェックし、必要に応じてスレッドを強制終了できます。

タスク<>を拡張して、この機能を追加することができます。

+0

r1versideに関する多くの記事を掲載している[Stephen Cleary](https://blog.stephencleary.com/)の優れたブログを読んでください。これも私の問題を解決しましたが、もっとそうであるようにOlexiyの答えに行く予定ですシンプル。ありがとうございました。私は十分な担当者がいないので、あなたに+1を与えることができませんでした:| – Nitheesh

関連する問題