【问题标题】:Cancelling all tasks when a new one is created创建新任务时取消所有任务
【发布时间】:2013-11-15 14:06:55
【问题描述】:

当列表框的部分项目更改时,我有以下任务运行。

当用户更改选择并开始新任务时,我正在尝试取消正在运行的任何任务。我似乎可以弄清楚为什么代码不起作用。

代码

CancellationTokenSource cts;
// The event handeler for when the user makes a selection in the list box 
private async void lb1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    clearfileds();

    if (cts != null)
       { cts.Cancel(); }

    cts = new CancellationTokenSource();

    var token = cts.Token;
    string sid = lb1.SelectedItem.ToString();

    try
    {   
        var series = await LoadSeriesAsync(token, Int32.Parse(sid));
        var poster = await LoadPosterAsync(series.PosterBanners[0]);

        UpdateSeries(series);
        if (File.Exists(poster))
        {
            ImageSource imageSource = new BitmapImage(new Uri(poster));
            imgPoster.Source = imageSource;
        }
    }
    catch (OperationCanceledException)
    {MessageBox.Show("we cancell some thing");}

    catch (FormatException)
    {MessageBox.Show("Please enter a valid series id");}

}


private async Task<TvdbSeries> LoadSeriesAsync(CancellationToken ct, int _seriesId)
    {  TvdbSeries seriesloaded = null;
       CancellationToken token = ct;

        Task<TvdbSeries> SeriesLoadTask = Task.Run(() =>
        {   
            m_tvdbHandler = new TvdbHandler(CacheProvider, "49E28C3EB13EB1CF");
            m_tvdbHandler.InitCache();
            token.ThrowIfCancellationRequested();

            try
            {   seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true);
                //Just for the test 
                System.Threading.Thread.Sleep(9000);
            }

            catch (OperationCanceledException)
            { }

            catch (TvdbInvalidApiKeyException ex)
            { MessageBox.Show(ex.Message);}
            catch (TvdbNotAvailableException ex)
            { MessageBox.Show(ex.Message);}

            return seriesloaded;
        });

        try
        { seriesloaded = await SeriesLoadTask; }

        catch (OperationCanceledException)
                {}
        return seriesloaded;
    }


 private  async Task<string> LoadPosterAsync(object _param)
        {
            string posterpath ;
            Task<string> PosterLoad = Task.Run(() =>
            {

                TvdbPosterBanner banner = (TvdbPosterBanner)_param;
                banner.LoadBanner();
                posterpath = CacheFolder + @"\" + banner.SeriesId + @"\img_posters_" + (banner.BannerPath).Replace(@"posters/", "");
                return posterpath;
            });


            try
            { posterpath = await PosterLoad; }

            catch (OperationCanceledException)
                {   
                    posterpath = "";
                }
            return posterpath;
        }

所以我试图让 LoadSeriesAsync 取消所有其他正在运行的事件,然后只有在 LoadSeriesAsync 允许完成时才运行 LoadPosterAsync (用户在加载之前不会更改选择)。

【问题讨论】:

  • 您能否更具体地了解“不工作”?
  • 对不起,任务没有取消
  • 您需要在 LoadSeriesAsync 中手动检查token.IsCancellationRequested - 请参阅stackoverflow.com/a/3713113/43846
  • Thread.Sleep(9000) 不是对异步代码的正确模拟。它会冻结你的用户界面。并且不要在运行昂贵的代码之前检查取消,在运行它时检查它
  • @Hans Passant 嗨,我应该在代码中的哪个位置检查是否正在调用取消令牌?你介意编辑我的例子来告诉我你的意思吗?

标签: c# .net-4.5 c#-5.0


【解决方案1】:

我正在尝试让 LoadSeriesAsync 取消所有其他正在运行的事件,然后仅在允许 LoadSeriesAsync 完成时才运行 LoadPosterAsync

所以,请在致电LoadPosterAsync 之前检查令牌:

var series = await LoadSeriesAsync(token, Int32.Parse(sid));
token.ThrowIfCancellationRequested();
var poster = await LoadPosterAsync(series.PosterBanners[0]);

附带说明,您应该将token 向下传递给任何长时间运行的操作,例如TvdbHandler.GetSeries

另外,catch (OperationCanceledException) { } 通常是个坏主意;通常,所需的语义是允许取消传播。

【讨论】:

  • 我尝试了您的建议,但似乎没有取消任务。我在seriesloaded = m_tvdbHandler.GetSeries 之前放了一个睡眠,这样当我更改选择时,它会在快速更改选择时减慢任务我看到有多个任务并且没有取消。这就是screen of tasks 的样子。
  • 正如我在回答中提到的,您需要修改 GetSeries 以便它接受取消令牌。
  • 还有其他方法吗,因为我无法更改 GetSeries,因为它的功能来自其他人制作的自定义 dll,所以我无法控制代码。
  • @justinf:没有取消不可取消代码的好方法。唯一真正的选择是将不可取消的代码加载到一个单独的进程中,并在需要取消时将其杀死。
  • 您介意更新您的答案以显示如何做到这一点吗?感谢您的帮助,很高兴知道正确的做事方式。
【解决方案2】:

使用 Thread 并在选择时检查 Thread.IsAlive 是否等于 true Thread.Abort() 然后 Thread.Start();容易

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    相关资源
    最近更新 更多