PostMessaage and UI hangs
- Hi,
I've created an MFC application with one worker thread. The worker thread frequently post message to UI thread to update its control. During this period, UI does not receive input message such as mouse or keyboard messages. The UI receive input message when worker thread is stopped.
I've read in MSDN that PostMessage has higher priority than input message. My requirement is that I want my window to process input message while its controls are being updated.
If I reduce the frequency of PostMessaage, the problem is solved, but that's not my requirement.
I've tried another non-queued message SendNotifyMessage() from worker thread, but that also does not work.
I am uploading my sample application. Is there any way to filter out some messages? Please help me out.
Thank you.
uploads/27862/uithreadtest.zip
All Replies
I think you have to avoid putting of multiple update messages. Since PeekMessage cannot be used from threads, you can consider another way. For example define a common flag (volatile bool mFlag), which will be true when there is a pending update message. Use appropriate thread synchronisation.
The body of posting loop can look like this:
::EnterCriticalSection(&mCritSec);
// . . . Update data . . .
if(!mFlag)
{
pDlg->PostMessage(WM_UPDATE_DLG, 0, 0);
mFlag = true;
}
::LeaveCriticalSection(&mCritSec);
The handler can look like this:
::EnterCriticalSection(&mCritSec);
// . . . Update controls . . .
mFlag = false;
::LeaveCriticalSection(&mCritSec);
- You are spamming your own message queue. Updates like this should be done when the the application is idle, that is when the message que is empty. A solution how OnIdle can be implemented in CDialog can be found here.
- Hi,
Thank you for your quick reply, but that doesn't solve my problem because if I use critical section, only one thread can use it at a time which makes application slow. I am actually enumerating drives and showing file count, folder count, and path. This is job of worker thread while UI thread' job is to show these information. If i use critical section, the worker thread's performance will be hampered, and I don't want to do that. Some other suggestion please.
Thank you. - Hi,
Nice suggestions, but that doesn't solve my problem. Actually, I have to enumerate drives in worker thread, and I've to show file count, folder count, and file path on UI while enumeration is going on. If I do this in OnIdle(), the information will be shown on UI even after worker thread finishes enumeration. Please suggest some other solution.
Thank you. unsigned int WINAPI SearchThreadFn( PVOID pvContext ) { if (NULL == pvContext) { return 0; } CuithreadtestDlg *pDlg = (CuithreadtestDlg *)pvContext; for (int i = 0; i < 10000; i++) { _stprintf(pDlg->m_szFileCnt, _T("%d"), i); _stprintf(pDlg->m_szFldrCnt, _T("%d"), i * i); _stprintf(pDlg->m_szPath, _T("%s"), _T("C:\\abc\\xyz\\dbf\\test.txt")); } wcscpy( pDlg->m_szFileCnt, _T("") ); wcscpy( pDlg->m_szFldrCnt, _T("") ); wcscpy( pDlg->m_szPath, _T("") ); return 0; } bool CuithreadtestDlg::OnIdle(LONG lCount) { if ( ::IsWindow(m_Stc_FileCount.m_hWnd) ) m_Stc_FileCount.SetWindowText(m_szFileCnt); if ( ::IsWindow(m_Stc_FolderCount.m_hWnd) ) m_Stc_FolderCount.SetWindowText(m_szFldrCnt); if ( ::IsWindow(m_Stc_Path.m_hWnd) ) m_Stc_Path.SetWindowText(m_szPath); return false; } LRESULT CuithreadtestDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { DWORD QueueStatus; LRESULT resValue = 0; bool OnIdleRetVal = true; if(message == WM_IDLE) { OnIdleRetVal = OnIdle((UINT)wParam); if(!OnIdleRetVal) wParam = 0; } else resValue = CDialog::WindowProc(message, wParam, lParam); QueueStatus = GetQueueStatus(QS_ALLINPUT); if(HIWORD(QueueStatus) == 0) PostMessage(WM_IDLE, wParam + (OnIdleRetVal ? 1 : 0), 0); return resValue; }
- Hi,
Thanks for your effort. I tried it in my application, but UI updates are quite non-interactive. UI is updated less frequently. I've tried WM_TIMER, using this UI update is quite interactive & UI doesn't hang as well.
So how about using WM_TIMER will 1000 ms interval, in which UI will be updated. I've read in MSDN that WM_TIMER message is picked up from message queue when there is no another pending message in the queue. So I think, it's like OnIdle. Well, what is the difference between these both technique, and is there any other issue.
Any suggestion please.
Thank you.


