How to Wait for Canceled Task to Finish?

前端 未结 2 2093
孤街浪徒
孤街浪徒 2020-12-18 18:24

I obviously don\'t know what I\'m doing when it comes to parallel programming with .NET 4.0. I have a simple Windows app that starts a task to do some mindless work (outputt

相关标签:
2条回答
  • 2020-12-18 18:42

    You would normally just use Task.Wait (instead of WaitAll), as it's a single task. and then handled the exception appropriately:

    private void stopButton_Click(object sender, EventArgs e)
    {
        cts.Cancel();
        try
        {
            t.Wait();  // This will throw
        }
        catch (AggregateException ae)
        {
           ae.Handle<OperationCanceledException>(ce => true);
        }
    
        statusTextBox.Text = "Output ended.";
    }
    

    When you cancel a Task, the OperationCanceledException will get wrapped into an AggregateException and be thrown as soon as you call Wait() or try to get the Task's Result (if it's a Task<T>).


    Purely for your information - This is one place, especially given what you're doing here, where C# 5 simplifies things. Using the new async support, you can write this as:

    // No need for "t" variable anymore 
    // private Task t;
    
    
    private async void startButton_Click(object sender, EventArgs e)
    {
       statusTextBox.Text = "Output started.";
    
       // Create the cancellation token source.
       cts = new CancellationTokenSource();
    
       try
       {
          // Create & start worker task.
          await Task.Run(() => DoWork(cts.Token));
          statusTextBox.Text = "Output ended.";
       }
       catch(OperationCanceledException ce) 
       {
          // Note that we get "normal" exception handling
          statusTextBox.Text = "Operation canceled.";
       }
    }
    
    private void stopButton_Click(object sender, EventArgs e)
    {
       // Just cancel the source - nothing else required here
       cts.Cancel();
    }
    
    0 讨论(0)
  • 2020-12-18 19:01

    Sorry, not enough reputation to just add a question as a comment to that answer. I wanted to ask how a work-around is considered an answer.

    Doesn't the code in the answer rely on some sort of user interface tweak to keep the user from starting more than one background process at a time? That's always a problem, of course.

    Here, I present an alternative that answer the question that is stated. It shows how to wait for the cancellation request to finish. It does this in a way that still lets the UI screw things up if it is not managed well, but has code that actually waits after the cancellation, if that is what is really needed. This is an excerpt from a larger C# class:

    AutoResetEvent m_TaskFinishedEvent = new AutoResetEvent( false );
    private IAsyncAction m_Operation = null;
    
    private Task WaitOnEventAsync( EventWaitHandle WaitForEvent )
    {
        return Task.Run( () => { WaitForEvent.WaitOne(); } );
    }
    
    public async void Start()
    {
    if( m_Operation != null )
        {
            // Cancel existing task
            m_Operation.Cancel();
            // Wait for it to finish. This returns control to the UI.
            await WaitOnEventAsync( m_TaskFinishedEvent );
        }
        // Start the background task.
        m_Operation = ThreadPool.RunAsync( WorkerMethod );
    }
    
    private void WorkerMethod( IAsyncAction operation )
    {
        while( m_Operation.Status != AsyncStatus.Canceled )
            ; // Add real work here.
    
        m_TaskFinishedEvent.Set();
    }
    

    This code relies on an event object to signal that the task is mostly finished. The WorkerMethod() code has not returned yet, but all useful work is done when the event is signaled.

    I did not provide a Stop() function because of how I use this code. The code to do the wait would just go in that Stop() function if that was how the code needs to work.

    Yes, you cannot use a regular Wait() function because of the cancellation exception. But the accepted answer is more of a work-around, no offense (and maybe I'm wrong?).

    0 讨论(0)
提交回复
热议问题