[英]In a Qt app, where my worker thread is the “main” thread, how can I communicate with the GUI thread
[英]How can worker threads communicate with main UI thread?
工作線程與主UI線程通信的最佳方式是什么?
簡介:我的C ++ / MFC應用程序是基於對話框的。 要進行冗長的計算,主UI線程會創建多個工作線程。 當工作線程在計算中進展時,它們會將進度報告給主UI線程,然后顯示進度。
這適用於數字進度值,它們位於共享內存中(由工作人員編寫,由UI讀取),但我遇到了文本進度消息的問題。 我嘗試過的解決方案已經過了幾次迭代,但似乎都沒有。
我讓UI線程傳遞指向工作者控件的指針,工作人員直接更新了UI。 這不是很有效,似乎是錯誤的方法。
我讓工作人員使用SendMessage向UI線程的窗口發送消息。 這陷入僵局。 (在處理完消息之前,SendMessage不會返回。)
與(2)相同,除了將PostMessage用於UI線程的窗口。 這工作了一段時間,然后消息丟失了。 (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
使用WaitForMultipleObjects調用中的主線程,不會處理任何消息,也不會更新任何控件或其他窗口。 解決方案是:不要那樣做。
在GUI上發布進度報告沒有太多意義,比用戶可以同意的更快。 當其他線程中存在大量活動時,通常使用GUI計時器輪詢線程中的進度變量,因此每次更新GUI控件,比如500ms。
這是定時器輪詢實際上有利的極少數時間之一。 您可以獲得peridoc進度報告,而不會有更新GUI GUI消息隊列的危險。 例如,uTorrent客戶端(其中存在大量網絡活動)使用此方案 - 嘗試更新收到的每個網絡協議單元上的GUI下載統計信息肯定會填充GUI。
(5)中的緩沖方案應該有效。 我經常通過將對象指針加載到LPARAM或WPARAM中來將大數據項傳輸到主GUI線程,在工作線程中新建它們並在顯示后在GUI中刪除它們。 你的(5)應該有效,至少減少了進度數據傳輸的開銷。 我只能假設要顯示的數據量仍然太大,因此GUI線程仍然無法跟上:(
Windows上的MFC工作線程有多個與主線程通信的選項。 您有標准的線程信令和同步原語 (互斥,信號量, 事件 ),易於使用的PostMessage ,以及更高性能的I / O完成端口機制。
// syncronization
{
CSingleLock lock(&sharedCriticalSection,TRUE);
sharedList.push_back(msg);
}
// other thread(s) are blocked/pending or you send an event or message to signal
// messages
Data* data = new Data(payload);
PostMessage(hWnd, REGISTERED_MESSAGE, 0, (LPARAM)data);
// target window handles message and deletes data
// if it is not blocked or too slow and the queue overflows
// skipping lots of IO completion port boilerplate and showing the key methods
messagePort = CreateIoCompletionPort(...);
...
GetQueuedCompletionStatus(messagePort,...);
...
PostQueuedCompletionStatus(messagePort,...);
如果您阻止或忙碌等待線程完成,它們都不會完成太多工作或提高您的性能或響應能力。
評論你的意見:
您的問題的答案:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.