2016-08-11 74 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); 
    }