【问题标题】:Async process start and wait for it to finish异步进程启动并等待它完成
【发布时间】:2010-10-11 07:09:47
【问题描述】:

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

  1. 启动处理文件的进程 (process.StartInfo.FileName = fileName;)
  2. 等待用户关闭进程或一段时间后放弃线程
  3. 如果用户关闭进程,删除文件

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

例子:

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

【问题讨论】:

标签: c# .net multithreading process


【解决方案1】:

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

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

【讨论】:

  • 我有一个问题。如果我有一个函数 A() { ThreadPool.UnsafeQueueUserWorkItem((o) => { .... proc.WaitForExit(); ... } 并且在主要方法中我有这样的:A(); Console.Write (“aa”);例如......事情是console.write完成它的工作并且线程仍然没有完成它的工作......页面正在加载。它没有等待进程终止。我该怎么办? 谢谢大家
  • @Grace 很难仅凭此说...但是除非您等待等待工作线程,否则这不正是您期望的 i> 去看看?
  • 所以我应该等待线程从主方法终止?
  • @Grace 这取决于你在做什么;如果您正在做的 only 事情是等待进程退出,那么......为什么要在工作线程上这样做?基本上需要更多的上下文。否则我无法给出有用的答案。
  • :我的进程将文件转换为 .flv 并使用 javascript 播放它们。当我在没有 Thread.Sleep() 之后调用该函数时,我无法获得转换,也无法获得播放器,因为线程没有有时间在页面加载之前完成它的工作..但是当我在函数之后睡眠时,那就是我得到我的播放器的时候。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

    ProcessStartInfo info = new ProcessStartInfo();
    
    info.FileName = "notepad.exe";
    Process process = Process.Start(info);
    
    process.Exited += new EventHandler(process_Exited);
    Console.Read();
    

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

    【讨论】:

      【解决方案4】:

      我可能不会使用单独的进程来打开文件。相反,我可能会使用后台线程(如果我认为该操作需要很长时间并且可能会阻塞 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 中处理异步操作的方式。

      【讨论】:

      • 对不起,其实我的意思是进程应该处理文件,而不是打开它。我重写了这个问题。
      【解决方案5】:

      试试下面的代码。

      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
      }
      

      【讨论】:

      • 不确定它是否处理“或一段时间后放弃线程”
      猜你喜欢
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2020-10-04
      • 2019-05-31
      • 2021-12-10
      • 2017-07-09
      相关资源
      最近更新 更多