2016-08-11 45 views
0

目前我的代码从svn运行一个checkout,并使用两个任务将stdout和stderr重定向到一个文本框,如下所示。我希望能够在用户单击StopButton并能够取消下载时立即取消任务。据我所知,如果我更改了我的cmd.exe命令来说出诸如“暂停”之类的内容,并继续运行,直到用户单击某些内容为止,则可以使用StopButton取消该命令。我对C#很陌生,并试图理解为什么我可以取消该命令而不是svn下载。如何取消在C#中启动进程的异步任务?

这是我应该实现我的代码的方式还是应该尝试不同的方法?

非常感谢您的帮助!我真的很感激它!

public Form2() 
    { 
     InitializeComponent(); 

    } 

    private TaskCompletionSource<bool> _cancelTask; 

    private async Task RunProcess() 
    { 
     Process process = new Process 
     { 
      StartInfo = new ProcessStartInfo 
      { 
       FileName = "cmd.exe", 
       Arguments = "svn download" 
       UseShellExecute = false, 
       RedirectStandardOutput = true, 
       RedirectStandardError = true, 
       CreateNoWindow = false, 
      } 
     }; 


     Console.Write(URL); 
     process.Start(); 

     Task readerTasks = Task.WhenAll(
      ConsumeReader(process.StandardError), 
      ConsumeReader(process.StandardOutput)); 

     Task completedTask = await Task.WhenAny(readerTasks, _cancelTask.Task); 

     if(completedTask == _cancelTask.Task) 
     { 
      process.Kill(); 
      await readerTasks; 
      throw new TaskCanceledException(_cancelTask.Task); 
     } 
    } 

    private async Task ConsumeReader(TextReader reader) 
    { 
     char[] text = new char[512]; 
     int cch; 

     while ((cch = await reader.ReadAsync(text, 0, text.Length)) > 0) 
     { 
      textBox2.AppendText(new string(text, 0, cch)); 
     } 
    } 

    private async void Submit_Click(object sender, EventArgs e) 
    { 

     Submit.Enabled = false; 
     StopButton.Enabled = true; 
     _cancelTask = new TaskCompletionSource<bool>(); 

     try 
     { 
      await RunProcess(cts.Token); 
     } 
     catch (OperationCanceledException) 
     { 
      MessageBox.Show("The operation was cancelled"); 
     } 
     finally 
     { 
      _cancelTask = null; 
      Submit.Enabled = true; 
      StopButton.Enabled = false; 
     } 
    } 

    private void StopButton_Click(object sender, EventArgs e) 
    { 
     _cancelTask.SetCanceled(); 
    } 
+0

你正在发送一个kill信号给'cmd',而不是'svn'或其他任何子进程。如果你想要一个更“结构化”的方法来杀死外部进程的树,请查看[Job API](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161(v = vs。 85)的.aspx)。不过,你必须自己做p/Invokes来使用.NET。 –

+0

除了前面的注释之外,请注意,除非特意要与命令行解释器(cmd.exe)交互,否则可以直接运行'svn',并将'download'作为参数传递给该任务。上面的问题需要正确回答,需要一些人在杀死启动它的cmd.exe进程之后,实际上_knows_ svn'工具的功能,处理方式以及它的哪些部分仍在运行。但是我会首先尝试直接运行'svn',看看是否能够完成。 –

+0

Stephen Cleary和Peter Duniho你是完全正确的。如果我将文件名更改为“svn.exe”,它将终止该任务。非常感谢您在这个问题上的时间和精力! –

回答

0

我找到了解决办法,不知道这是最好的,但你可以启动另一个进程来启动命令行命令的taskkill杀死所有正在运行的.exe文件的的。我现在杀死了从cmd.exe调用的cmd.exe(父)和svn.exe(子)!

这只有在知道从父项开始的.exes时才有用,如果有更多的子项创建,最好找到不同的解决方案递归地去找到子项进程。

if(completedTask == _cancelTask.Task) 
    { 
     //process.Kill(); This would only kill the CMD.exe 
     Process exit = new Process 
      { 
       StartInfo = new ProcessStartInfo 
       { 
        FileName = "cmd.exe", 
        //Arguments = "/K Pause", 
        Arguments = "/C taskkill /f /im svn.exe & taskkill /f /im cmd.exe", 
        UseShellExecute = false, 
        RedirectStandardOutput = true, 
        RedirectStandardError = true, 
        CreateNoWindow = false, 
       } 
      }; 
      exit.Start(); 
     await readerTasks; 
     throw new TaskCanceledException(_cancelTask.Task); 
    }