Hanging process when run with .NET Process.Start -- what's wrong?
Solution 1
One standard issue: the process could be waiting for you to read its output. Create a separate thread to read from its standard output while you're waiting for it to exit. It's a bit of a pain, but that may well be the problem.
Solution 2
Jon Skeet is right on the money!
If you don't mind polling after you launch your svn command try this:
Process command = new Process();
command.EnableRaisingEvents = false;
command.StartInfo.FileName = "svn.exe";
command.StartInfo.Arguments = "your svn arguments here";
command.StartInfo.UseShellExecute = false;
command.StartInfo.RedirectStandardOutput = true;
command.Start();
while (!command.StandardOutput.EndOfStream)
{
Console.WriteLine(command.StandardOutput.ReadLine());
}
Solution 3
I had to drop an exe on a client's machine and use Process.Start to launch it.
The calling application would hang - the issue ended up being their machine assuming the exe was dangerous and preventing other applications from starting it.
Right click the exe and go to properties. Hit "Unblock" toward the bottom next to the security warning.
Solution 4
Based on Jon Skeet's answer this is how I do it in modern day (2021) .NET 5
var process = Process.Start(processStartInfo);
var stdErr = process.StandardError;
var stdOut = process.StandardOutput;
var resultAwaiter = stdOut.ReadToEndAsync();
var errResultAwaiter = stdErr.ReadToEndAsync();
await process.WaitForExitAsync();
await Task.WhenAll(resultAwaiter, errResultAwaiter);
var result = resultAwaiter.Result;
var errResult = errResultAwaiter.Result;
Note that you can't await the standard output before the error, because the wait will hang in case the standard error buffer gets full first (same for trying it the other way around).
The only way is to start reading them asynchronously, wait for the process to exit, and then complete the await by using Task.WaitAll
Solution 5
I know this is an old post but maybe this will assist someone. I used this to execute some AWS (Amazon Web Services) CLI commands using .Net TPL tasks.
I did something like this in my command execution which is executed within a .Net TPL Task which is created within my WinForm background worker bgwRun_DoWork
method which holding a loop with while(!bgwRun.CancellationPending)
. This contains the reading of the Standard Output from the Process via a new Thread using the .Net ThreadPool class.
private void bgwRun_DoWork(object sender, DoWorkEventArgs e)
{
while (!bgwRun.CancellationPending)
{
//build TPL Tasks
var tasks = new List<Task>();
//work to add tasks here
tasks.Add(new Task(()=>{
//build .Net ProcessInfo, Process and start Process here
ThreadPool.QueueUserWorkItem(state =>
{
while (!process.StandardOutput.EndOfStream)
{
var output = process.StandardOutput.ReadLine();
if (!string.IsNullOrEmpty(output))
{
bgwRun_ProgressChanged(this, new ProgressChangedEventArgs(0, new ExecutionInfo
{
Type = "ExecutionInfo",
Text = output,
Configuration = s3SyncConfiguration
}));
}
if (cancellationToken.GetValueOrDefault().IsCancellationRequested)
{
break;
}
}
});
});//work Task
//loop through and start tasks here and handle completed tasks
} //end while
}
Comments
-
struppi over 2 years
I wrote a quick and dirty wrapper around svn.exe to retrieve some content and do something with it, but for certain inputs it occasionally and reproducibly hangs and won't finish. For example, one call is to svn list:
svn list "http://myserver:84/svn/Documents/Instruments/" --xml --no-auth-cache --username myuser --password mypassword
This command line runs fine when I just do it from a command shell, but it hangs in my app. My c# code to run this is:
string cmd = "svn.exe"; string arguments = "list \"http://myserver:84/svn/Documents/Instruments/\" --xml --no-auth-cache --username myuser --password mypassword"; int ms = 5000; ProcessStartInfo psi = new ProcessStartInfo(cmd); psi.Arguments = arguments; psi.RedirectStandardOutput = true; psi.WindowStyle = ProcessWindowStyle.Normal; psi.UseShellExecute = false; Process proc = Process.Start(psi); StreamReader output = new StreamReader(proc.StandardOutput.BaseStream, Encoding.UTF8); proc.WaitForExit(ms); if (proc.HasExited) { return output.ReadToEnd(); }
This takes the full 5000 ms and never finishes. Extending the time doesn't help. In a separate command prompt, it runs instantly, so I'm pretty sure it's unrelated to an insufficient waiting time. For other inputs, however, this seems to work fine.
I also tried running a separate cmd.exe here (where exe is svn.exe and args is the original arg string), but the hang still occurred:
string cmd = "cmd"; string arguments = "/S /C \"" + exe + " " + args + "\"";
What could I be screwing up here, and how can I debug this external process stuff?
EDIT:
I'm just now getting around to addressing this. Mucho thanks to Jon Skeet for his suggestion, which indeed works great. I have another question about my method of handling this, though, since I'm a multi-threaded novice. I'd like suggestions on improving any glaring deficiencies or anything otherwise dumb. I ended up creating a small class that contains the stdout stream, a StringBuilder to hold the output, and a flag to tell when it's finished. Then I used ThreadPool.QueueUserWorkItem and passed in an instance of my class:
ProcessBufferHandler bufferHandler = new ProcessBufferHandler(proc.StandardOutput.BaseStream, Encoding.UTF8); ThreadPool.QueueUserWorkItem(ProcessStream, bufferHandler); proc.WaitForExit(ms); if (proc.HasExited) { bufferHandler.Stop(); return bufferHandler.ReadToEnd(); }
... and ...
private class ProcessBufferHandler { public Stream stream; public StringBuilder sb; public Encoding encoding; public State state; public enum State { Running, Stopped } public ProcessBufferHandler(Stream stream, Encoding encoding) { this.stream = stream; this.sb = new StringBuilder(); this.encoding = encoding; state = State.Running; } public void ProcessBuffer() { sb.Append(new StreamReader(stream, encoding).ReadToEnd()); } public string ReadToEnd() { return sb.ToString(); } public void Stop() { state = State.Stopped; } }
This seems to work, but I'm doubtful that this is the best way. Is this reasonable? And what can I do to improve it?
-
struppi over 15 yearsYeah, I can run the exact command without prompts from the command line. This call returns in well under a second from teh command line, and I have tried waiting up to 30 seconds in my app with no love, so it sure seems to be AWOL.
-
scottm over 15 yearsHave you tried using the defualtsettings for the StreamReader, ie StreamReader sr = new StreamReader(proc.StandardOutput);
-
user1703401 over 15 yearsYeah, that's it. There's only a 2k output buffer, it will hang when you don't empty it. BeginOutputReadLine + BeginErrorReadLine solves it.
-
struppi over 15 yearsYeah, I can't do that in general because I need the specific UTF-8 encoding for the xml, but in specific cases where the default encoding works, there was no change.
-
Dom M. almost 12 yearsHow did you know it was only a 2k output buffer? In my application, I'm seeing this hang occur on one server, but not another... wondering if it could be due to the size of the output buffer.
-
Bob Horn about 11 yearsI know this is four years later, but I'm struggling to understand how the above code can work.
command.Start()
is synchronous, right? If that's the case, how will the above code ever get to the next line? -
Justin Tanner almost 11 years
Process.Start
is synchronous, but once it executes a command it returns, leaving it to the user to check when the command has completed. -
Aron Lorincz over 8 yearsLooks like that was it! I call
process.StandardOutput.ReadToEndAsync();
andprocess.StandardError.ReadToEndAsync();
, after startingcmd.exe
, then it does not hang. -
Xena almost 8 yearsYou can also choose not to read stdout at all (if you don't need it). command.StartInfo.RedirectStandardOutput = false does the trick for me.
-
Xena almost 8 yearsThe above does not solve the problem of Process.Start hanging... but it does tell us when the process is done executing its command before moving on.
-
Jack about 5 yearsI know it's an old question but I'm having this issue on windows 7 only. I'm using
Process.BeginOutputReadLine()
can still be the process waiting for read the stdout? -
Jon Skeet about 5 years@Jack: I'm afraid I don't know, and don't have a Windows 7 box to test on
-
Jack about 5 years@JonSkeet: Any other guess on what could be causing the process to hang only on windows 7? I'm hours on this, clueless on what could be. I start the process like this pastebin.com/PBMtqGQT
-
Jon Skeet about 5 yearsNot without being able to reproduce it myself, no.
-
Jack about 5 years@JonSkeet I find out. While the called process is supposed to not read anything from stdin, it seems was done so. I find out by setting
RedirectStandardInput = true
and closing the stdin streamproc.StandardInput.Close();
. I left this comment for those that have had same issue as me =) -
Aviad P. over 2 yearsThis is it - I used the following, instead of more threads: gist.github.com/paviad/f2d635fa269561a15c05d79b46c33895
-
Jon Skeet over 2 years@AviadP.: You might want to add that as a separate answer. Bear in mind this answer was first written in 2009, long before async/await :)
-
Aviad P. over 2 yearsWell, tbh, it might be prettier to include the process exit task in the wait all...
-
Moolie about 2 yearsDon't have
WaitForExitAsync
in .NET 4, ButReadToEndAsync
is available and helped me a lot!