【问题标题】:When does windows signal a process handle?windows什么时候发出进程句柄的信号?
【发布时间】:2009-01-22 08:19:11
【问题描述】:

我实现了一个自我升级过程,我的主应用程序 exe 启动一个更新程序 exe,在命令行上将句柄传递给它自己。然后应用程序exe调用ExitProcess退出,更新程序在传入的句柄上调用WaitForSingleObject等待应用程序exe终止。

WaitForSingleObject 确实在等待。直到应用程序调用 ExitProcess,更新程序才会停止。

但是,有时,当更新程序尝试使用新版本覆盖应用程序 dll 时,我会收到一个文件锁定错误,我的更新程序的当前版本将其视为不可恢复的错误并终止。似乎包含任意 sleep(100) 足以绕过这个“问题”,但我真的很讨厌这样的代码。真的很讨厌。

在我看来很奇怪,在主应用程序还活着的情况下可以向进程句柄发出信号以锁定 dll 文件。

【问题讨论】:

    标签: windows winapi synchronization


    【解决方案1】:

    当应用程序代码退出时,进程会发出信号。操作系统可能需要更多时间才能完全卸载该进程。发出信号的目的是说“我已经完成了我需要做的事情”,它更有效地释放其他可能有真正有用的东西要做的代码,而不是让那些代码等待操作系统做一些家务。

    【讨论】:

    • 似乎——实际上——只要有一个有效的退出代码可以从 GetExitCode() 返回,进程句柄就会发出信号。但是,就常见用例而言,最可能等待进程句柄的应用程序是安装程序/更新程序,它们需要知道何时能够删除内容。
    【解决方案2】:

    正如另一个答案所指出的,当进程停止执行时,进程句柄会收到信号,并且操作系统可能需要更长的时间来释放 DLL。

    你说得对,依赖 Sleep(100) 是个坏主意。你应该像这样在一个循环中覆盖你的 DLL:

    BOOL UpdateDll(LPCTSTR dll_name, WHATEVER whatever) {
      int tries = 150;
      while (tries--) {
        if (TryUpdateDll(dll_name, whatever))
          return TRUE;
        Sleep(200);
      }
      return FALSE;
    }
    

    这会持续尝试卸载 DLL 30 秒,然后放弃。即使系统处于重负载状态,30 秒也应该足够了,但仍然可以保护您的更新程序不会永远挂起。 (如果 UpdateDll 返回 FALSE,请务必向您的用户提供有意义的错误消息,说明违规 DLL 的名称。)

    如果您在搞乱 COM,在退出之前调用 CoFreeUnusedLibraries 也可能会有所帮助。 (http://msdn.microsoft.com/en-us/library/ms679712.aspx) 坦率地说,我不知道 COM 是否会在您的进程退出后保留 DLL,但最好是安全的。

    底线是 Win32 API 有很多奇怪之处。只要您能找到可接受的解决方案,您就不必处理每个案例。显然 Sleep(100) 可能会中断,但我似乎可以接受 30 秒的轮询循环。

    【讨论】:

      【解决方案3】:

      可能是 DLL 在当时被其他进程锁定。对此进行测试的一种方法是在发生这种情况时生成一份报告,说明 DLL 中的任何内容。

      【讨论】:

        【解决方案4】:

        大约 6 个月前,在一些防病毒软件中看到了这些问题。尝试不使用 AV,至少确保 AV 是最新的。

        【讨论】:

          【解决方案5】:

          如果您使用的任何 DLL 正在使用线程,如果您不显式卸载它们,它们可能无法足够快地终止(或加入) - 如果您使用 LoadLibrary 显式加载它们当然会发生这种情况

          看这里: http://msdn.microsoft.com/en-us/library/ms682596(VS.85).aspx

          特别是这一行:

          ... DLL 被卸载时 进程终止或调用 FreeLibrary 功能及参考 计数变为零。如果过程 终止作为的结果 TerminateProcess 或 TerminateThread 函数,系统不调用 DLL 入口点函数。

          【讨论】:

            【解决方案6】:

            可能为您解决的问题...虽然您无法替换正在使用的 dll,但您可以重命名它。因此,如果您有需要替换的 dll,但由于某种原因正在使用中,请将其重命名为 .delete 或类似的名称。进行更新,然后让您的主程序搜索任何 .delete 文件并在启动时将其删除。

            -不要

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-03-13
              • 2013-10-24
              • 2019-06-05
              • 2015-07-17
              • 2016-03-26
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多