7

我有一个在后台运行的进程并且有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并让我的代码“继续”。提前终止进程在我的应用程序中很少见,但我仍然需要它工作,所以这个实现必须做。

}

4

2 回答 2

9

WaitForExit是对操作系统的直接调用,以等待进程句柄发出信号。当一个进程终止时,WaitForExit 就会完成。Kill是一个直接调用,TerminateProcess这是一个不问任何问题的杀戮。如果使用正确,完成WaitForExit后将返回Kill

因此,您的代码中还有其他一些错误。创建一个更简单的重现,您将看到问题消失。该错误隐藏在代码的复杂性中。

或者,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并等待两个可等待对象中的任何一个变为已发出信号。看看WaitForExit内部做了什么,看看你如何自己实现这个(我会复制出ProcessWaitHandle内部的类)。

WaitForExit(TimeSpan.FromMilliseconds(100))一个更简单的解决方案是循环调用并exited每次检查标志。

于 2013-09-09T23:00:57.413 回答
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**");
于 2013-09-09T21:55:59.507 回答