异步进程启动并等待它完成

时间:2009-03-04 15:35:18

标签: c# .net multithreading process

我是.net中线程模型的新手。你会用什么:

  1. 启动处理文件的进程(process.StartInfo.FileName = fileName;)
  2. 等待用户关闭进程或在一段时间后放弃该线程
  3. 如果用户关闭了该过程,请删除该文件
  4. 启动进程并等待应该在与主线程不同的线程上完成,因为此操作不应该影响应用程序。

    示例:

    我的应用程序生成一个HTML报告。用户可以右键单击某处并显示“查看报告” - 现在我在临时文件中检索报告内容并启动处理html文件的过程,即默认浏览器。问题是我无法清理,即删除临时文件。

5 个答案:

答案 0 :(得分:60)

“等待必须是异步的” - 我不是想搞笑,但这不是一个矛盾吗?但是,由于您要开始ProcessExited事件可能有所帮助:

ProcessStartInfo startInfo = null;
Process process = Process.Start(startInfo);
process.EnableRaisingEvents = true;
process.Exited += delegate {/* clean up*/};

如果你想实际等待(超时等),那么:

if(process.WaitForExit(timeout)) {
    // user exited
} else {
    // timeout (perhaps process.Kill();)
} 

等待异步,或许只是使用不同的线程?

ThreadPool.QueueUserWorkItem(delegate {
    Process process = Process.Start(startInfo);
    if(process.WaitForExit(timeout)) {
        // user exited
    } else {
        // timeout
    }
});

答案 1 :(得分:18)

为这个旧问题添加高级替代方案。如果要等待进程退出而不阻塞任何线程并仍然支持超时,请尝试以下操作:

    public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
    {
        ManualResetEvent processWaitObject = new ManualResetEvent(false);
        processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

        RegisteredWaitHandle registeredProcessWaitHandle = null;
        registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
            processWaitObject,
            delegate(object state, bool timedOut)
            {
                if (!timedOut)
                {
                    registeredProcessWaitHandle.Unregister(null);
                }

                processWaitObject.Dispose();
                tcs.SetResult(!timedOut);
            },
            null /* state */,
            timeout,
            true /* executeOnlyOnce */);

        return tcs.Task;
    }

同样,与接受的答案相比,此方法的优势在于您不会阻止任何线程,从而减少了应用的开销。

答案 2 :(得分:4)

尝试以下代码。

public void KickOffProcess(string filePath) {
  var proc = Process.Start(filePath);
  ThreadPool.QueueUserWorkItem(new WaitCallBack(WaitForProc), proc);
}

private void WaitForProc(object obj) {
  var proc = (Process)obj;
  proc.WaitForExit();
  // Do the file deletion here
}

答案 3 :(得分:0)

我可能不会使用单独的进程来打开文件。相反,我可能会使用后台线程(如果我认为操作需要很长时间并且可能阻止UI线程)。

private delegate void FileOpenDelegate(string filename);

public void OpenFile(string filename)
{
   FileOpenDelegate fileOpenDelegate = OpenFileAsync;
   AsyncCallback callback = AsyncCompleteMethod;
   fileOpenDelegate.BeginInvoke(filename, callback, state);
}

private void OpenFileAsync(string filename)
{
   // file opening code here, and then do whatever with the file
}

当然,这不是一个好的工作示例(它什么都不返回),我还没有展示UI如何更新(你必须在UI级别使用BeginInvoke,因为后台线程无法更新UI线程)。但这种方法通常是我如何处理.Net中的异步操作。

答案 4 :(得分:0)

您可以在Process类

中使用Exited事件
ProcessStartInfo info = new ProcessStartInfo();

info.FileName = "notepad.exe";
Process process = Process.Start(info);

process.Exited += new EventHandler(process_Exited);
Console.Read();

在那种情况下,你可以处理你提到的操作