C# 使用 .NET Process.Start 运行时挂起进程——有什么问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/439617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hanging process when run with .NET Process.Start -- what's wrong?
提问by Chris Farmer
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.exe 周围写了一个快速而肮脏的包装器来检索一些内容并用它做一些事情,但对于某些输入,它偶尔和可重复地挂起并且不会完成。例如,一个调用是 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:
当我只是从命令外壳执行此命令行时,该命令行运行良好,但它挂在我的应用程序中。我运行它的 C# 代码是:
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.
这需要完整的 5000 毫秒并且永远不会完成。延长时间没有帮助。在单独的命令提示符中,它会立即运行,所以我很确定这与等待时间不足无关。然而,对于其他输入,这似乎工作正常。
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:
我还尝试在此处运行单独的 cmd.exe(其中 exe 是 svn.exe,args 是原始 arg 字符串),但仍然发生挂起:
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:
我现在才开始着手解决这个问题。Mucho 感谢 Jon Skeet 的建议,这确实很有效。不过,由于我是一个多线程新手,所以我对我的处理方法还有另一个问题。我想就改进任何明显的缺陷或其他愚蠢的事情提出建议。我最终创建了一个包含 stdout 流的小类、一个用于保存输出的 StringBuilder 以及一个指示何时完成的标志。然后我使用了 ThreadPool.QueueUserWorkItem 并传入了我的类的一个实例:
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?
这似乎有效,但我怀疑这是最好的方法。这合理吗?我能做些什么来改善它?
采纳答案by Jon Skeet
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.
一个标准问题:进程可能正在等待您读取其输出。创建一个单独的线程以在您等待它退出时从其标准输出中读取。这有点痛苦,但这很可能是问题所在。
回答by scottm
I know my SVN repos can run slow sometimes, so maybe 5 seconds isn't long enough? Have you copied the string you are passing to the process from a break point so you are positive it's not prompting you for anything?
我知道我的 SVN 存储库有时会运行缓慢,所以也许 5 秒不够长?您是否从断点复制了您传递给进程的字符串,因此您肯定它不会提示您进行任何操作?
回答by Justin Tanner
Jon Skeet is right on the money!
If you don't mind polling after you launch your svn command try this:
乔恩·斯基特(Jon Skeet)在钱上是对的!
如果您在启动 svn 命令后不介意轮询,请尝试以下操作:
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());
}
回答by dynamiclynk
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.
我知道这是一个旧帖子,但也许这会对某人有所帮助。我使用它来使用 .Net TPL 任务执行一些 AWS (亚马逊网络服务)CLI 命令。
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.
我在我的命令执行中做了类似的事情,它是在 .Net TPL 任务中执行的,该任务是在我的 WinForm 后台工作bgwRun_DoWork
方法中创建的,该方法与while(!bgwRun.CancellationPending)
. 这包含使用 .Net ThreadPool 类通过新线程从进程读取标准输出。
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
}
回答by IrkenInvader
I had to drop an exe on a client's machine and use Process.Start to launch it.
我不得不在客户端的机器上放置一个 exe 并使用 Process.Start 来启动它。
The calling application would hang - the issue ended up being their machine assuming the exe was dangerous and preventing other applications from starting it.
调用应用程序将挂起 - 问题最终是他们的机器假设 exe 是危险的并阻止其他应用程序启动它。
Right click the exe and go to properties. Hit "Unblock" toward the bottom next to the security warning.
右键单击 exe 并转到属性。在安全警告旁边的底部点击“取消阻止”。