【问题标题】:Canceling a Process started via System.Diagnostics.Process.Start()取消通过 System.Diagnostics.Process.Start() 启动的进程
【发布时间】:2012-12-31 01:34:17
【问题描述】:

我正在编写一个应用程序,其中我有一个在BackgroundWorker 中运行的进程。我想支持从用户界面取消,但我没有看到一个简单的方法来做到这一点。

Process 实际上是一个运行时间相当长的命令行 exe。输出通过 Progress.OutputDataReceived 事件异步重定向,并用于向 GUI 报告进度。

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    using (var process = new Process())
    {
        //...

        process.Start()

        //...

        process.WaitForExit();
    }
}

private void CancelWorker()
{
    worker.CancelAsync();
    // where to actually listen for the cancellation???
}

除了StandardInput 之外,似乎没有办法让进程“侦听”来自主线程的任何输入,但除非应用程序本身响应特定输入中止。

有没有办法根据来自主线程的取消请求取消进程?

为了我在进程中运行的EXE,我可以调用Process.Close()退出而没有任何副作用,但是Process对象只有worker_DoWork()方法知道,所以我'出于取消目的,我需要跟踪 Process 实例...这就是为什么我希望可能有更好的方法。

(如果重要的话,我的目标是 .NET 3.5 以解决兼容性问题。)

【问题讨论】:

  • 您在 BG 工作人员中启动进程是否有原因?这通常是一个不需要很长时间的调用(正在启动的程序可能需要一段时间才能加载,但这将在它自己的进程中)。
  • 其实不是在后台worker中,而是在自定义的Async方法中,BackgroundWorker似乎更容易描述这种情况。但原因是这是在后台线程中运行的更大进程的一部分。
  • CancelAsync 将不起作用,因为线程在几毫秒内完成了它的工作,除非您在该 DoWork 方法中有一些繁重的负载。尽管using 是一种很好的做法,但由于您需要能够从代码中的其他位置访问Process,您可以有一个类级别的变量来保存Process 并调用Process.Close。只要记住当您的线程返回或不再需要该进程时对该进程调用Dispose
  • Process 中运行的 exe 是运行时间相当长的命令行工具,我试图从我的应用程序中执行它……平均而言,它可能需要 15 分钟或更长时间才能完成。它以异步方法运行的原因之一是允许进行进度报告。我无法直接从process_OutputDataReceived 事件处理程序报告进度,因为它位于不同的线程上,因此异步方法似乎是一个合乎逻辑的选择。

标签: c#


【解决方案1】:

合作取消需要收听BackgroundWorker.CancellationPendingBackgroundWorker.DoWork 事件。

How to: Use a Background Worker

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    using (var process = new Process())
    {
        //...

        process.Start()

        //...
        while(true)
        { 
            if ((sender as BackgroundWorker).CancellationPending && !process.HasExited)
            {
              process.Kill();
              break;
            }
            Thread.Sleep(100);
         }

        process.WaitForExit();
    }
}

【讨论】:

  • 很好的建议,但是由于while(true),除非收到取消,否则循环永远不会退出。我把它改成了while(!process.HasExited),它工作得很好,谢谢。
【解决方案2】:

试试这个,这可能对你有帮助,很简单

private System.Threading.TimerCallback worker;
private System.Threading.Timer workertimer ;
private void worker_DoWork()
{
   //You codes
}
private void StartWorker()
{
   worker = new System.Threading.TimerCallback(worker_DoWork);
   workertimer = new System.Threading.Timer(worker, null, 1000, 1000);
}

private void CancelWorker()
{
    worker.Dispose();
}

【讨论】:

  • 我看不到,process 是如何在 Dispose 方法中被杀死的。它是如何工作的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 2012-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多