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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/611094/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 10:14:03  来源:igfitidea点击:

Async process start and wait for it to finish

c#.netmultithreadingprocess

提问by Bogdan Gavril MSFT

I am new to the thread model in .net. What would you use to:

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

  1. start a process that handles a file (process.StartInfo.FileName = fileName;)
  2. wait for the user to close the process OR abandon the thread after some time
  3. if the user closed the process, delete the file
  1. 启动一个处理文件的进程(process.StartInfo.FileName = fileName;)
  2. 等待用户关闭进程或在一段时间后放弃线程
  3. 如果用户关闭了进程,删除文件

Starting the process and waiting should be done on a different thread than the main thread, because this operation should not affect the application.

启动进程和等待应该在与主线程不同的线程上完成,因为这个操作不应该影响应用程序。

Example:

例子:

My application produces an html report. The user can right click somewhere and say "View Report" - now I retrieve the report contents in a temporary file and launch the process that handles html files i.e. the default browser. The problem is that I cannot cleanup, i.e. delete the temp file.

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

采纳答案by Marc Gravell

"and waiting must be async" - I'm not trying to be funny, but isn't that a contradiction in terms? However, since you are starting a Process, the Exitedevent may help:

“并且等待必须是异步的”-我不是想搞笑,但这不是自相矛盾吗?但是,由于您正在启动Process,因此该Exited事件可能会有所帮助:

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

If you want to actually wait (timeout etc), then:

如果您想实际等待(超时等),则:

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

For waiting async, perhaps just use a different thread?

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

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

回答by JaredPar

Try the following code.

试试下面的代码。

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
}

回答by Chris Holmes

I would probably not use a separate process for opening a file. Instead, I'd probably utilize a background thread (if I thought the operation was going to take a long time and possible block the UI thread).

我可能不会使用单独的过程来打开文件。相反,我可能会使用后台线程(如果我认为该操作将花费很长时间并且可能会阻塞 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
}

Of course, this is not a good working example (it returns nothing) and I haven't shown how the UI gets updated (you have to use BeginInvoke at the UI level because a background thread cannot update the UI thread). But this approach is generally how I go about handling asynchronous operations in .Net.

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

回答by Pablo Retyk

You can use the Exitedevent in Process class

您可以Exited在 Process 类中使用该事件

ProcessStartInfo info = new ProcessStartInfo();

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

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

and in that event you can handle the operations you mentioned

在这种情况下,您可以处理您提到的操作

回答by Chris Gillum

Adding an advanced alternative to this old question. If you want to wait for a process to exit without blocking any thread and still support timeouts, try the following:

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

    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;
    }

Again, the advantage to this approach compared to the accepted answer is that you're not blocking any threads, which reduces the overhead of your app.

同样,与公认的答案相比,这种方法的优势在于您不会阻塞任何线程,从而减少了应用程序的开销。