从按钮取消异步任务

时间:2014-01-14 14:19:36

标签: c# async-await cancellationtokensource

我需要做的是取消正在运行异步的任务。

我一直在寻找,似乎无法绕过它。我似乎无法辨别它将如何实现到我当前的设置中。

这是我的代码,可以解雇我的任务。任何关于在何处或如何实施取消令牌的帮助将不胜感激。

    private async void startThread()
    {
        //do ui stuff before starting
        ProgressLabel.Text = String.Format("0 / {0} Runs Completed", index.Count());
        ProgressBar.Maximum = index.Count();

        await ExecuteProcesses();

        //sort list of output lines
        outputList = outputList.OrderBy(o => o.RunNumber).ToList();

        foreach (Output o in outputList)
        {
            string outStr = o.RunNumber + "," + o.Index;
            foreach (double oV in o.Values)
            {
                outStr += String.Format(",{0}", oV);
            }

            outputStrings.Add(outStr);
        }

        string[] csvOut = outputStrings.ToArray();

        File.WriteAllLines(settings.OutputFile, csvOut);
        //do ui stuff after completing.

        ProgressLabel.Text = index.Count() + " runs completed. Output written to file test.csv";
    }

    private async Task ExecuteProcesses()
    {
        await Task.Factory.StartNew(() =>
        {
            int myCount = 0;
            int maxRuns = index.Count();
            List<string> myStrings = index;
            Parallel.ForEach(myStrings,
                new ParallelOptions()
                {
                    MaxDegreeOfParallelism = settings.ConcurrentRuns
                }, (s) =>
                {
                    //This line gives us our run count.
                    int myIndex = myStrings.IndexOf(s) + 1;

                    string newInputFile = Path.Combine(settings.ProjectPath + "files/", Path.GetFileNameWithoutExtension(settings.InputFile) + "." + s + ".inp");
                    string newRptFile = Path.Combine(settings.ProjectPath + "files/", Path.GetFileNameWithoutExtension(settings.InputFile) + "." + s + ".rpt");

                    try
                    {
                        //load in contents of input file
                        string[] allLines = File.ReadAllLines(Path.Combine(settings.ProjectPath, settings.InputFile));


                        string[] indexSplit = s.Split('.');

                        //change parameters here
                        int count = 0;
                        foreach (OptiFile oF in Files)
                        {
                            int i = Int32.Parse(indexSplit[count]);
                            foreach (OptiParam oP in oF.Parameters)
                            {
                                string line = allLines[oP.LineNum - 1];
                                if (oP.DecimalPts == 0)
                                {
                                    string sExpression = oP.Value;
                                    sExpression = sExpression.Replace("%i", i.ToString());
                                    EqCompiler oCompiler = new EqCompiler(sExpression, true);
                                    oCompiler.Compile();
                                    int iValue = (int)oCompiler.Calculate();

                                    allLines[oP.LineNum - 1] = line.Substring(0, oP.ColumnNum - 1) + iValue.ToString() + line.Substring(oP.ColumnNum + oP.Length);
                                }
                                else
                                {
                                    string sExpression = oP.Value;
                                    sExpression = sExpression.Replace("%i", i.ToString());
                                    EqCompiler oCompiler = new EqCompiler(sExpression, true);
                                    oCompiler.Compile();
                                    double dValue = oCompiler.Calculate();
                                    dValue = Math.Round(dValue, oP.DecimalPts);

                                    allLines[oP.LineNum - 1] = line.Substring(0, oP.ColumnNum - 1) + dValue.ToString() + line.Substring(oP.ColumnNum + oP.Length);
                                }
                            }
                            count++;
                        }
                        //write new input file here
                        File.WriteAllLines(newInputFile, allLines);
                    }
                    catch (IOException ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }


                    var process = new Process();
                    process.StartInfo = new ProcessStartInfo("swmm5.exe", newInputFile + " " + newRptFile);
                    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                    process.Start();
                    process.WaitForExit();

                    Output output = new Output();
                    output.RunNumber = myIndex;
                    output.Index = s;
                    output.Values = new List<double>();

                    foreach(OutputValue oV in OutputValues) {
                         output.Values.Add(oV.getValue(newRptFile));
                    }

                    outputList.Add(output);

                    //get rid of files after run
                    File.Delete(newInputFile);
                    File.Delete(newRptFile);

                    myCount++;
                    ProgressBar.BeginInvoke(
                        new Action(() =>
                            {
                                ProgressBar.Value = myCount;
                            }
                    ));
                    ProgressLabel.BeginInvoke(
                        new Action(() =>
                            {
                                ProgressLabel.Text = String.Format("{0} / {1} Runs Completed", myCount, maxRuns);
                            }
                    ));
                });
        });
    }

1 个答案:

答案 0 :(得分:10)

支持取消的最佳方法是将CancellationToken传递给async方法。然后按下按钮可以取消令牌

class TheClass
{
  CancellationTokenSource m_source;

  void StartThread() { 
    m_source = new CancellationTokenSource;
    StartThread(m_source.Token);
  }

  private async void StartThread(CancellationToken token) { 
    ...
  }

  private void OnCancelClicked(object sender, EventArgs e) {
    m_source.Cancel();
  }
}

但这还不够。在startThread注册为已取消

后,StartProcessCancellationToken方法都需要更新以协同取消任务