4

バックグラウンド タスクとして実行される「インデックス サービス」を持つ WPF アプリケーションを開発しています。インデックス サービスは、フォルダーを監視する FileSystemWatcher を利用します。ファイルが変更されると、インデックス サービスはファイルの内容を読み取り、インデックスを更新します (私は Lucene.Net を使用しています)。私のインデックス サービスはシングルトンで、アプリケーションの起動時に次のように開始されます。

new TaskFactory().StartNew(_indexingService.StartService);

メソッドは次のStartService()ようになります。

private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);

public void StartService()
{
    var watcher = new FileSystemWatcher
    {
        // Set the properties
    };
    watcher.Changed += UpdateIndexes();

    _resetEvent.WaitOne();
}

アプリケーションが閉じているときに、このメソッドを呼び出すつもりです。これにより、インデックス サービスのバックグラウンド タスクが終了することがわかります。

public void StopService()
{
    _resetEvent.Set();
}

まず第一に、これはアプリケーションの存続期間中に実行する必要があるバックグラウンド タスクを開始および停止するための正しい "パターン" ですか?

第二に、このシャットダウンはどれほど「優雅」でしょうか? ウォッチャーChangedイベント ハンドラーが起動し、ファイルを反復処理して、ファイルを読み取り、インデックスを更新しているとします。タスクが停止した場合、この処理はフローの途中で中止されますか、それともイベント ハンドラー メソッドが最初に完了まで実行されますか?

4

3 に答える 3

4

キャンセル トークンを使用できます。

  CancellationTokenSource CancelationToken = new CancellationTokenSource();
  new TaskFactory().StartNew(_indexingService.StartService,CancelationToken,
                              TaskCreationOptions.LongRunning)   
.ContinueWith(TaskCancelationCallBack,TaskContinuationOptions.OnlyOnCanceled);   

以下を使用して、アプリケーション内の任意の場所でトークンをキャンセルします。

 CancellationTokenSource.Cancel();

トークンがキャンセルされているかどうかを確認し、内部からタスクのキャンセル例外をスローできます。

if (CancelationToken.IsCancellationRequested) {    

    CancelationToken.Token.ThrowIfCancellationRequested(); 
}         

ContinueWith コールバックでタスクのステータスを取得できます。

private void TaskCancelationCallBack(System.Threading.Tasks.Task task)
{
  if (task.Status == System.Threading.Tasks.TaskStatus.Canceled)
  {
         //Canceled
  } 
}

EDIT : この場合TaskContinuationOptions.OnlyOnCanceled、TaskCancelationCallBack のチェックが不要になるように を使用しました。その前提でのみ解雇されます。

于 2013-10-03T08:37:50.230 に答える
1

@カルロス・ランデラス

ThrowIfCancellationRequested は、キャンセルが要求されたかどうかをチェックするため、同じことをチェックする if ステートメントに埋め込むのは冗長です。

http://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken.throwifcancellationrequested.aspx

This method provides functionality equivalent to:
    if (token.IsCancellationRequested) 
        throw new OperationCanceledException(token);
于 2014-02-11T10:10:43.227 に答える
0

waitOne を呼び出した場合、タスクはいずれにせよ終了します。

バックグラウンド タスクで実際に何かを実行するには、ある時点で次のように処理するループが必要になります。

void ProcessItems()
{
    while(workItems.Count > 0)
    {
        ProcessItem(workItems[0]);
    }
}

優雅に救済したい場合は、2 つのことを行うことができます。私の例では、フラグがあります。

bool m_IsRunning = true;
public void Stop()
{
    m_IsRunning = false;
}
void ProcessItems()
{
    while(workItems.Count > 0 && m_IsRunning)
    {
            ProcessItem(workItems[0]);
    }
}

Task Parallel Library を使用すると、CancellationToken.

Task クラスでは、キャンセルには、キャンセル可能な操作を表すユーザー デリゲートと、キャンセルを要求したコードとの間の連携が含まれます。キャンセルの成功には、CancellationTokenSource.Cancel メソッドを呼び出す要求コードと、タイムリーに操作を終了するユーザー デリゲートが含まれます。次のいずれかのオプションを使用して、操作を終了できます。

  • 単にデリゲートから戻ることによって。多くのシナリオでは、これで十分です。ただし、この方法で「キャンセル」されたタスク インスタンスは
    、Canceled 状態ではなく、RanToCompletion 状態に遷移します。

  • OperationCanceledException をスローし、キャンセルが要求されたトークンを渡します。これを行う
    には、ThrowIfCancellationRequested メソッドを使用することをお勧めします。この方法でキャンセルされたタスク
    は Canceled 状態に遷移し、呼び出し元のコードはこれを使用して、タスクが キャンセル要求
    に応答したことを確認できます。

http://msdn.microsoft.com/en-us/library/dd997396.aspx

于 2013-10-03T08:46:27.513 に答える