【发布时间】:2013-10-09 06:16:19
【问题描述】:
工作线程与主 UI 线程通信的最佳方式是什么?
总结:我的 C++/MFC 应用程序是基于对话框的。为了进行冗长的计算,主 UI 线程创建了几个工作线程。当工作线程在计算中进行时,它们会将其进度报告给主 UI 线程,然后主 UI 线程会显示进度。
这适用于共享内存中的数字进度值(由工作人员编写,由 UI 读取),但我在处理文本进度消息时遇到问题。我尝试的解决方案经过了多次迭代,但似乎都没有奏效。
我让 UI 线程将指向控件的指针传递给工作人员,工作人员直接更新了 UI。这不是很有效,而且似乎是错误的方法。
我让工作人员使用 SendMessage 向 UI 线程的窗口发送消息。这就陷入了僵局。 (在消息被处理之前,SendMessage 不会返回。)
与 (2) 相同,但在 UI 线程的窗口中使用 PostMessage。这工作了一段时间,然后消息丢失了。 (PostMessage 立即返回。)进一步调查显示消息队列的配额已超过默认值 10,000。
-
我增加了消息队列的配额(注册表中的变量 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\USERPostMessageLimit),但丢失消息的数量没有改变。
我让每个工作线程在 4 KB 缓冲区中缓冲消息,并在缓冲区填满时使用 PostMessage。这失败了,因为 UI 线程从未收到任何消息。当我将缓冲区大小增加到 64 KB 时也是如此。
工作线程以“最低”优先级运行,而 UI 线程以“正常”优先级运行。工作线程正在发送带有类似代码的消息
UIMessage *pUI=new UIMessage; // so it won't go out of scope (main dialog will delete it)
pUI->buffer=traceLineBuffer; pUI->nOutputs=traceN;
BOOL ok=::PostMessage(hWndMainDlg,TraceLineMsg,(WPARAM)pUI, NULL/*lParam*/);
并且 UI 正在接收它们的代码,例如
BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
...
ON_MESSAGE(TraceLineMsg,OnTraceLineMsg)
...
END_MESSAGE_MAP()
LRESULT CMainDlg::OnTraceLineMsg(WPARAM wParam, LPARAM lParam)
{
UIMessage *pUI=(UIMessage *)wParam;
char *p=pUI->buffer;
// PROCESS BUFFER
delete[] pUI->buffer;
delete pUI;
return 0;
}
问题:
在可能会出现数千个文本报告的情况下,员工发布进度报告的首选方式是什么?
为什么不能增加队列中发帖的配额?
为什么主 UI 线程似乎从未收到缓冲区中的消息,即使传输它们的机制与发布单个报告相同?
64 位 Windows 7、Visual Studio 2010、本机 C++/MFC
【问题讨论】:
-
发布消息是一种方法。但是您是否考虑过大幅降低消息数量?为什么不只每 100 或 1000 条消息更新一次?
-
您采取的方法是正确的,但是发送足够多的消息以超过队列限制确实没有意义。唯一可能导致无法接收已发布消息的是超出队列限制或主线程被阻塞,例如在 Sleep 或 WaitFor.. 调用中。发布这些消息时,主线程在做什么?您是否还为每条消息分配另一个 traceLineBuffer ?
-
koodawg:我确实减少了消息的数量,通过在 (5) 中缓冲它们。
-
ScottMcP-MVP:主线程在 WaitForMultipleObjects 中,直到工作线程完成。也许这就是问题所在。是的,为每条消息分配了一条新消息和缓冲区,从我在 OnTraceLineMsg 中删除它们可以看出。
-
我应该说 WaitForMultipleObjects 是为了让工作线程完成:
WaitForMultipleObjects(nThreadsActive,threadHandles,TRUE/*wait for all*/,INFINITE);
标签: c++ multithreading mfc