如何确保线程在终结器完成之前不终止

How to ensure thread is not terminated before finalizer completes

我有一个非托管 class,它是 运行 子 Win32 window 的消息循环。当程序关闭时,它会启动托管 class 的终结器,该终结器保存对此 class 的非托管引用。因为另一个线程依赖于这个class,所以我需要finalizer等到消息循环线程完成一个循环后退出终止。但是,对于 GC 终结器线程,我的超时循环显然花费了太长时间,或者主线程终止破坏了整个进程。

有没有办法告诉 GC 不要让终结器的线程超时? IE。 - 我需要终结器线程在终结器中阻塞一段时间,以便它可以完成消息循环线程的终止,然后释放非托管资源。

这是我的终结器,因此您可以了解发生了什么:

PONms::NestedWin32::
!NestedWin32()
{

    if (msgLoop->IsAlive)
    {
        winProcess->EndThread(); // blocks and waits for message loop thread to terminate
                                // and GC apparently doesn't like this causeing the
                                // entire process to terminate here.
    }
    if (childHandle != nullptr)
    {
        DestroyWindowCore(childHandle);
    }
    if (winProcess != nullptr)
    {
        delete winProcess; // memory leak due to resource not being released
    }
}

我想我的做法是错误的,只是希望代码能够正常运行并且终结器能够完成。

这是我用来轮询另一个线程以查看它是否已终止的简单方法:

void PONms::NestedWin32UM::
EndThread()
{
    int timeOut = 5000;
    threadContinue = false;
    SendNotifyMessage(childWin, WM_CLOSE, 0, 0);
    while (threadActive && timeOut > 0)
    {
        POCPP::Threading::SleepThreadOne();
        timeOut--;
    }
}
int timeOut = 5000;

这与终结器线程超时的默认 CLR 策略非常不匹配。您有 2 秒的时间来完成工作。现代处理器上大约有 100 亿条指令。我们看不到 SleepThreadOne() 做了什么,但是 Sleep(1) 没有休眠 1 毫秒。默认睡眠粒度为 15.625 毫秒,因此您最终将等待长达 78 秒。

从技术上讲,您可以通过自定义托管 CLR、ICLRPolicyManager::SetTimeout() method、OPR_FinalizerRun 设置来延长超时时间。但是,实际上,如果您不能用 100 亿条指令破解它,那么扩展它不太可能带来缓解。

调试没那么简单,这2秒就这么匆匆过去了。查看结构修复。不要使用 bool 来同步代码,使用事件(CreateEvent winapi 函数)。和 WaitForSingleObject() 超时等待它被设置。最大使用 1000 毫秒,以便为终结器线程提供足够的喘息空间。不要太客气地要求消息循环退出,WM_CLOSE 太友好了。代码很容易用 "Save changes?" 消息框来响应它,这肯定会失败。使用 PostQuitMessage()。或者根本不打扰,程序应该通过 UI 终止,你似乎需要另辟蹊径。