从 ui-thread 显示窗口有时会阻塞主 ui-thread

Posted

技术标签:

【中文标题】从 ui-thread 显示窗口有时会阻塞主 ui-thread【英文标题】:Displaying window from ui-thread sometimes blocks the main ui-thread 【发布时间】:2014-05-06 17:23:58 【问题描述】:

我不是 MFC 专家,当然也不是多线程专家,但我仍然想了解这种奇怪的行为。在某些地方,当我在我的应用程序中创建 MFC ui 线程时,它会启动并且可以显示消息框,但主 ui 线程被阻止。但是有时如果我创建线程,则线程执行会停止,直到主 ui 线程再次非阻塞。

当然,情况已经弥补。主ui线程的阻塞,象征着某种同步,而ui线程的messagebox则象征着一些更复杂的ui对话框。

这更像是一个理论问题。我主要感兴趣的是为什么会发生这种情况?这是一个例子:

class MessageBoxThread : public CWinThread

    DECLARE_DYNCREATE( MessageBoxThread );
public:
    virtual BOOL InitInstance()
    
        CWinThread::InitInstance();
        AfxMessageBox(_T("Some text"));
        return TRUE;
    
;

IMPLEMENT_DYNCREATE( MessageBoxThread , CWinThread );


void testing()

    MessageBoxThread* pMessageBoxThread = new MessageBoxThread ();
    pMessageBoxThread->CreateThread();

    Sleep(10000);

    AfxMessageBox(_T("It Worked!"));

因此,就示例而言,如果我将“测试”函数放入 CWinApp::InitInstance 中,它会按预期工作(首先显示“某些文本”,然后在 10 秒后显示“成功!”)。但是,如果我将其放入应用程序深处的随机位置,则可能会在 10 秒睡眠后两个消息框同时出现。什么可能导致这种行为?

【问题讨论】:

【参考方案1】:

我不是 MFC 粉丝,但知道 Win32 我可以看到正在发生的事情。将其置于“深度”可能意味着在某些窗口消息处理代码中调用 testing() 函数——该代码在主 UI 线程上运行并处理泵送消息。因此,您正在让您的 UI 线程进入睡眠状态,在这种情况下,这类似于消息框或模式对话框的作用。因此,您的消息泵(我认为在 CWinApp 中实现)被此 Sleep() 阻塞,等待您完成对消息的处理以响应您的代码被执行(不管是什么消息)。

【讨论】:

你是对的。我实际上是从主 ui 线程中的消息处理程序调用 testing() 。但是,我不确定我是否理解您答案的第二部分。如果我阻塞了我的主 ui 线程,那么为什么我的新 ui 线程会出现问题?那不是应该有自己的消息处理循环吗?【参考方案2】:

好的,我终于找到了答案。当有人创建 ui 线程时,该人必须初始化包含 ui 线程基本窗口的 m_pMainWnd 成员。如果你不这样做,框架将使用应用程序提供的主窗口,这是主 ui 线程中的一个。由于那个是因为 Sleep() 方法而被阻塞的,所以另一个 ui 线程只有在主线程没有被阻塞时才会响应。

【讨论】:

以上是关于从 ui-thread 显示窗口有时会阻塞主 ui-thread的主要内容,如果未能解决你的问题,请参考以下文章

从 PyQt 的主窗口打开 Ui_Form

如何追踪阻塞主(UI)线程的调用?

QT中UI主窗口如何与子线程相互传递参数

CoreData从后台线程读取数据仍然阻塞UI界面的原因及解决

UIActionSheet 应该从弹出窗口中调用,但从主屏幕底部显示

UI 元素添加到控件集合时抛出异常