问题
Currently my code runs a checkout from svn and redirections the stdout and stderr to a textbox using two tasks as seen below. I want to be able to cancel the task immediately when a user clicks the StopButton and be able to cancel the download. I understand that if I changed my cmd.exe command to say something such as "Pause", which continues to run until a user clicks something, I can cancel this command with the StopButton. I am very new to C# and trying to understand why I can cancel that command and not the svn download.
Is this a way I should be implementing my code or should I try a different method?
Thanks so much for the help! I truly appreciate it!
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();
}
回答1:
I found a solution, not sure if this is the best, but you can start another process to start the command line command taskkill to kill all of the .exe's that are running. I now kill the cmd.exe (parent) and the svn.exe (child) that was called from the cmd.exe!
This is only useful if you know the .exes that are started from the parent if there were many more children created it would be best to find a different solution to recursively go and find the children processes.
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);
}
来源:https://stackoverflow.com/questions/38903661/how-to-cancel-a-async-task-that-starts-a-process-in-c