2012-02-28 16 views
1

データ記憶域から検索結果を取得するような非同期操作を考えてみます。現在は、現在保留中の検索操作をキャンセルして新しい検索操作を開始することができます。実際にはアクティブな検索が置き換えられます。主に検索パラメータが変更されたためです。非同期操作を停止して置き換えを開始する

私の検索では、TPL(.NET 4.0)新しいタスク経由で開始し、最終的に続けていると、もちろんUI-コンテキストにUI-メソッドを呼び出すコールバックを、持っています。

検索TASTが実行されている間、検索ボタンを、もう一度押すのであれば、私は、まず、現在のタスクを停止し、それが終了するのを待つ必要があります。私がUIスレッドから行うと、UIスレッドのWait()がブロックするので、デッドロックが発生する可能性があります。そのため、Invoke()は決して実行されません。

したがって、私の現在のソリューションでは、私は中止し、新しいものを実行/終了するタスクを実行するのを待ち、別のタスクを、開始します。これはちょっと嵩張り、扱いにくいと感じています。私はこのような仕組みが頻繁に必要なので、それ以上のエレガントな方法はないと思います。

は、だから私は多分、シナリオのこの種のために使用可能です枠組みメカニズムをしないのですか?または、より推奨される方法は何ですか?

答えて

4

私は、これはあなたが探しているものであると信じています。私はそのコードにコメントしているので、ほとんどの推論はコードに埋め込まれています。

基本的に、あなたの継続機能を使って、準備されたタスクをスピンアップさせてください。

Task currentTask; 
CancellationTokenSource cancelTokenSource; 
CancellationToken cancelToken; 
Task newTask; 
CancellationTokenSource newCancelTokenSource; 
CancellationToken newCancelToken; 

public Form1() 
{ 
    InitializeComponent(); 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    if(currentTask != null && currentTask.Status == TaskStatus.Running) 
    { 
     //Cancel the running task 
     cancelTokenSource.Cancel(); 
     //Prepare a new Task to be triggered when the other cancels 
     //You could store new tasks/tokens in a dictionary if you wanted,also 
     //A new cancel token is always needed since the old stays cancelled 
     newCancelTokenSource = new CancellationTokenSource(); 
     newCancelToken = newCancelTokenSource.Token; 
     newTask = new Task(()=>LongRunningTask(), newCancelToken); 

     //Continue that deals with both cancel and completion 
     //There is a different way to deal with this below, also 
     newTask.ContinueWith((previousTask)=> 
     { 
      if(previousTask.Status == TaskStatus.Cancelled) 
      { 
       label1.Text = "New Task Cancelled, Another New Starting"; 
       BeginNewTask(); 
      } 
      else 
       label1.Text = "New Task Ran To Completion"; 
     }, 
     //If cancelled token is passed, it will autoskip the continue 
     new CancellationTokenSource().Token, TaskContinuationOptions.None, 
     //This is to auto invoke the UI thread 
     TaskScheduler.FromCurrentSynchronizationContext()); 
    } 
    else 
    { 
     cancelTokenSource = new CancellationTokenSource(); 
     cancelToken = cancelTokenSource.Token; 
     //Start a fresh task since none running 
     currentTask = Task.Factory.StartNew(()=>LongRunningTask(), 
      cancelToken); 

     //OnCancelContinue 
     currentTask.ContinueWith((previousTask)=> 
     { 
      label1.Text = "First Task Cancelled, New Starting"; 
      BeginNewTask(); 
     }, 
     //If cancelled token is passed, it will autoskip the continue 
     new CancellationTokenSource().Token, 
     TaskContinuationOptions.OnlyOnCancelled, 
     //This is to auto invoke the UI thread 
     TaskScheduler.FromCurrentSynchronizationContext()); 

     //OnCompleteContinue 
     currentTask.ContinueWith((previousTask)=> 
     { 
      label1.Text = "First Task Ran To Completion"; 
     }, 
     //If cancelled token is passed, it will autoskip the continue 
     new CancellationTokenSource().Token, 
     TaskContinuationOptions.OnlyOnRanToCompletion, 
     //This is to auto invoke the UI thread 
     TaskScheduler.FromCurrentSynchronizationContext()); 
    } 
} 

private void LongRunningTask() 
{ 
    for(int i = 0; i < 60; i++) 
    { 
     if(cancelToken.IsCancellationRequested) 
      cancelToken.ThrowIfCancellationRequested(); 
     Thread.Sleep(1000); 
    } 
} 

private void BeginNewTask() 
{ 
    //Since the old task is cancelled, reset it with the new one 
    //Probably should do some error checks 
    currentTask = newTask; 
    cancelTokenSource = newCancelTokenSource; 
    cancelToken = newCancelToken; 
    //This is to make sure this task does not run on the UI thread 
    currentTask.Start(TaskScheduler.Default); 
} 
+0

感謝。だから、私は正しい方向に行きました。 :-) –

+0

Yahは、この作品の鍵です。 –

関連する問題