我有一个在后台运行且有WaitForExit()
的进程,因为持续时间可能会有所不同,我需要等到它完成。有时,我需要在它完成之前结束它,并通过类事件触发.Kill()
命令。 .HasExited
属性更改为true,但代码永远不会通过WaitForExit()
行。
public class MyProcess: Process
{
private bool exited;
public MyProcess()
{
...
}
public void Start(args...)
{
try
{
base.StartInfo.FileName = ...
base.StartInfo.Arguments = ...
base.StartInfo.RedirectStandardOutput = true;
base.StartInfo.UseShellExecute = false;
base.StartInfo.CreateNoWindow = true;
base.EnableRaisingEvents = true;
base.Exited += new EventHandler(MyProcessCompleted);
base.OutputDataReceived += new DataReceivedEventHandler(outputReceived);
base.Start();
this.exited = false;
base.BeginOutputReadLine();
while (!this.exited)
{
if ()
{
...
}
else
{
base.WaitForExit(); ---- after the process is killed, it never gets past this line.
}
...
}
}
catch (Exception ex)
{
...
}
}
private void MyProcessCompleted(object sender, System.EventArgs e)
{
exited = true;
...
}
private void outputReceived(object sender, DataReceivedEventArgs e)
{
...
}
//Subscription to cancel event
public void ProcessCanceled(object sender, EventArgs e)
{
...
if (!exited)
{
base.Kill();
}
}
}
\
更新:
我的进程启动基于java的文件传输客户端并执行传输。该过程显示在任务管理器中,Kill()
不会结束它。由于我并不真正关心结束这个过程,而是需要我的程序转到下一个“任务”,我在Close()
之后添加了Kill()
,它释放了WaitForExit
并让我的代码“继续前进”。在我的应用程序中,提前终止该过程将是罕见的,但我仍然需要它才能工作,所以这个实现将不得不这样做。
}
答案 0 :(得分:9)
WaitForExit
是对操作系统的直接调用,等待进程句柄发出信号。当流程终止时,WaitForExit
将完成。 Kill
是对TerminateProcess
的直接调用,这是一个没有问题的杀戮。如果使用正确WaitForExit
将在Kill
完成后返回。
因此您的代码中还有其他一些错误。创建一个更简单的repro,你会发现问题消失了。该错误隐藏在代码的复杂性中。
或者,WaitForExit
确实返回但您没有注意到。或者,Kill
从未执行或失败。同样,简化代码将揭示问题。你能把它带到一个5行的复制品吗?我怀疑你可以,但如果你这样做,我会再看看。
试试这个:
Process p = Process.Start("notepad.exe");
Task.Factory.StartNew(() => { Thread.Sleep(1000); p.Kill(); });
p.WaitForExit();
更新
在你指定的评论中,杀死ping确实有效,但是杀死你的特殊进程却没有。原因通常是不可取消的IO。 Windows内核保持流程,直到所有IO完成。好消息是该进程最终会死亡,Kill
返回后代码不会运行。坏消息是资源清理工作还没有完全完成。
您现在需要确保代码可以继续运行,尽管WaitForExit
没有返回。为此,我在Kill
完成后设置了一个ManualResetEvent。而不是调用WaitForExit
,而是使用Process.Handle
属性获取进程句柄,并等待两个waitable中的任何一个发出信号。看看WaitForExit
内部做了什么,看看你如何自己实现这个(我将复制出内部的ProcessWaitHandle
类。)
更简单的解决方案是在循环中调用WaitForExit(TimeSpan.FromMilliseconds(100))
并每次检查exited
标记。
答案 1 :(得分:0)
你会尝试一个更干净的代码(我想)。测试.....
Process proc = null;
//Kill process after 3 seconds
Task.Run(() =>
{
Task.Delay(3000).Wait();
if(proc!=null && proc.HasExited==false) proc.Kill();
});
var psi = new ProcessStartInfo()
{
FileName = "ping.exe",
Arguments = "-t 127.0.0.1",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
};
proc = new Process();
proc.StartInfo = psi;
proc.OutputDataReceived += (s,e) =>
{
Console.WriteLine(e.Data);
};
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
Console.WriteLine("**killed**");