【问题标题】:Who owns CWinThread after it was created by AfxBeginThread?CWinThread 由 AfxBeginThread 创建后谁拥有它?
【发布时间】:2012-03-15 16:12:00
【问题描述】:

我正在使用AfxBeginThread 启动一个线程。这将返回一个指向新 CWinThread 对象的指针。

MSDN 声明此指针为 NULL,如果线程创建失败,它将释放所有内容。但是,一旦线程在定期启动后退出,CWinThread 对象仍然存在。我不确定我是否应该删除 CWinThread 对象,或者这是否由 MFC 本身完成(尽管看起来并非如此)。

仅供参考,线程不太可能退出,因为它应该一直运行到应用程序结束。但是,由于我将其用作线程池的一部分,因此我不希望 CWinThread 永远挂起 aorund。

【问题讨论】:

    标签: c++ mfc


    【解决方案1】:

    清理 CWinThread 对象的责任取决于它的 m_bAutoDelete 值。默认是删除自身。对于火灾并忘记短期运行的线程,这很好。它会自行清理。

    如果您的线程长时间运行并且需要被告知是时候退出或与之交互,您将希望 CWinThread 句柄保持有效并且不指向自删除对象。

    如果您将 m_bAutoDelete 设置为 FALSE,则您声明对删除它负责。为了安全地使用返回的指针,您应该按照 Joseph Newcomer 在他的Using Worker Threads 文章中的建议创建暂停并将其设置为 FALSE,然后再恢复。

       thread = AfxBeginThread(proc, this, 
                           THREAD_PRIORITY_NORMAL, // default: use it
                           0,     // default stack size 
                           CREATE_SUSPENDED); // let us set auto delete
       if(thread) { // protect against that rare NULL return
           thread->m_bAutoDelete = FALSE;
           thread->ResumeThread();
       }
    

    【讨论】:

    • 这是唯一正确的答案。其他两个答案是错误的,可能会导致未定义的行为。
    • 如果您有一个 m_bAutoDelete = TRUE 的 GUI 线程,并且您观察到尽管用户单击了主窗口的“关闭”按钮,但该线程并未退出,则可能需要调用 PostQuitMessage()在 PostNcDestroy() 中。
    • 另请注意,如果您自己在线程之后进行清理 (m_bAutoDelete = FALSE),您仍需要等待线程退出后再删除对象
    【解决方案2】:

    我从不相信 CWinThread 会自行清理。我通常会创建线程并告诉 MFC 我会进行清理,特别是在程序关闭时:

    CWinThread *thread = AfxBeginThread(...); 
    thread->m_bAutoDelete = FALSE;
    

    但是,您必须保存线程指针,否则您会出现内存泄漏。

    【讨论】:

    • 谢谢,我刚刚发现了 m_bAutoDelete 成员,并按照您和@fontanini 的建议进行操作。 +1
    • 这个答案是错误的。当这段代码尝试设置m_bAutoDelete 时,CWinThread 对象可能已经自己删除了。请参阅@jla 关于如何正确使用此技术的回答。
    • 我不同意答案是错误的。答案的关键是 m_bAutoDelete,为简洁起见,示例中的参数为“...”。 CREATE_SUSPENDED 也很重要,如果不是,您的评论是正确的。我同意@jila 的回答更完整。
    【解决方案3】:

    如果您的线程仍在运行,则不应删除它。停止后,只需在 AfxBeginThread 返回的指针上使用运算符 delete 即可释放线程使用的内存:

    CWinThread *thread = AfxBeginThread(...);
    /* ... */
    // now wait for it to terminate
    WaitForSingleObject(thread->m_hThread, INFINITE); 
    delete thread;
    

    您应该存储CWinThread 指针直到您的线程/应用程序结束,以便您可以释放为它们分配的内存。否则会出现内存泄漏。

    【讨论】:

    • 这个答案是错误的。在线程终止时,CWinThread 将关闭线程句柄,并删除自己。因此,此代码可能会在关闭的句柄上调用WaitForSingleObject,这是未定义的行为,或者它可能会尝试删除已被删除的对象。正确的方法是在 suspended 线程上使用m_bAutoDelete,正如@jla 的回答中所解释的那样。
    猜你喜欢
    • 2016-01-26
    • 2018-10-23
    • 2019-10-27
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    相关资源
    最近更新 更多