首页 > 解决方案 > wxWidgets CallAfter 唤醒 macOS 上的主 UI 线程?

问题描述

我在 macOS 下的 GitHub 的 wxWidgets master 下收到“从后台线程调用的 UI API”错误。

UI API called from background thread Group
file:///DeveloperLibs/wxWidgets-3.1.3/src/osx/cocoa/evtloop.mm: runtime: UI API called from background thread: -[NSApplication postEvent:atStart:] must be used from main thread only

#0  0x00000001004e5908 in wxGUIEventLoop::WakeUp() at /DeveloperLibs/wxWidgets-3.1.3/src/osx/cocoa/evtloop.mm:390
#1  0x00000001004651fd in wxApp::WakeUpIdle() at /DeveloperLibs/wxWidgets-3.1.3/src/osx/carbon/app.cpp:439
#2  0x00000001001d0cf7 in wxWakeUpIdle() at /DeveloperLibs/wxWidgets-3.1.3/src/common/appbase.cpp:1108
#3  0x00000001003a6a03 in wxEvtHandler::QueueEvent(wxEvent*) at /DeveloperLibs/wxWidgets-3.1.3/src/common/event.cpp:1318
#4  0x000000010017a09c in void wxEvtHandler::CallAfter<myPanel::Finish()::$_1>(myPanel::Finish()::$_1 const&) at /DeveloperLibs/wxWidgets-3.1.3/include/wx/event.h:3668
#5  0x0000000100179fba in myPanel::Finish() at /Volumes/Macintosh HD04/Users/rich/Projects/thing/myPanel.cpp:88

.... 下面的行只是不相关的 thread/_pthread_start 内容。

在内部myPanel::Finish()(当它完成时由线程调用),我正在使用:

void myPanel::Finish()
{
  this->GetEventHandler()->CallAfter([this]()
  {
    stopButton->Disable();
    GoToResultsPanel();
  });
}

问题不在于我的 lambda 中的代码,而是实际的 CallAfter 调用,因为它调用wxWakeUpIdle()了,然后以调用wxApp::WakeUpIdle()结束,以wxGUIEventLoop::WakeUp()调用结束[NSApp postEvent:event atStart:FALSE];

这样,我的后台线程正在唤醒 UI 线程。状态的文档wxEvtHandler::CallAfter

请注意,在其他非 GUI 线程中使用 CallAfter() 是安全的,但该方法将始终在主 GUI 线程上下文中调用。

这似乎不是这里的情况?我究竟做错了什么?

编辑:顺便说一句,这是在 macOS Catalina 下。在 macOS Sierra 和 wxWidgets 3.1.3 下,我没有收到关于相同代码的运行时警告。evtloop.mm 代码是相同的,但在这个较旧的 macOS 下不会产生警告!

标签: c++multithreadingmacoswxwidgets

解决方案


推荐阅读