-
June 9th, 2011, 04:53 AM
#1
Problem: Creation of a modless CDialog in a thread.
Hello,
I’m developing an application composed of three threads:
- The “main” thread, with the user interface and other stuff.
- A “working” thread that handles messages to perform actions.
- A “monitoring” thread that is used to load / unload monitoring panels.
The “main” thread starts both “working” and “monitoring” threads.
The user can ask to open/close monitoring panels, so the “main” thread posts messages to the “monitoring” thread. When a panel is opened or closed, it registers/unregisters itself to the “working” thread for notifications about the performed actions.
When the application is closed, the “main” thread stops the “monitoring” and the “working” threads by posting messages.
In normal processing, every thing works fine.
My problem is the following:
When a message is posted to the “monitoring” thread during a panel creation (panels are modless CDialog), the “monitoring” thread blocks on the Create(IDD); of the CDialog. More precisely in dlgcore.cpp, in method:
BOOL CWnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd, HINSTANCE hInst)
on line:
hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate, pParentWnd->GetSafeHwnd(), AfxDlgProc);
This problem is very easy to reproduce if I use following code:
::PostThreadMessage ( monitoringThreadId, MSG_OpenPanel, 0, 0 );
::PostThreadMessage ( monitoringThreadId, MSG_ClosePanel, 0, 0 );
In my log I can see the both post message. Only the first one handled and its processing stay blocked on the CDialog Create(IDD) method, as explained above.
Thanks for your help.
-
June 9th, 2011, 05:05 AM
#2
Re: Problem: Creation of a modless CDialog in a thread.
Why do you have a "monitoring" thread at all? Do all your user interface processing in the main thread. The only thing a worker thread should do with user interfaces is post messages to windows.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
June 9th, 2011, 06:17 AM
#3
Re: Problem: Creation of a modless CDialog in a thread.
As D_Drmmr already pointed out you should move all the UI attributes into the main GUI thread.
Besides:
Originally Posted by Cariboo42
... I use following code:
Code:
::PostThreadMessage ( monitoringThreadId, MSG_OpenPanel, 0, 0 );
::PostThreadMessage ( monitoringThreadId, MSG_ClosePanel, 0, 0 );
In my log I can see the both post message. Only the first one handled and its processing stay blocked ...
You could only PostThreadMessage is the thread you were posting to had the message pump. "Worker" thread has no message pump. Only MFC so called "UI" thread has.
You may want to look at the MDSN articles:
PostThreadMessage Function (note its Remark section)
AfxBeginThread
as well as Using Worker Threads essay
Victor Nijegorodov
-
June 9th, 2011, 07:17 AM
#4
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by D_Drmmr
Why do you have a "monitoring" thread at all? Do all your user interface processing in the main thread. The only thing a worker thread should do with user interfaces is post messages to windows.
In fact, I develop an application with plug-ins and I decided to use Threads (and PostThreadMessages) for communication with my plug-ins. It also prevents the “main” thread to freeze due to time-consumer plug-ins.
What I really want to understand is why a thread is blocking when it receives a message while it is creating a CDialog.
-
June 9th, 2011, 07:23 AM
#5
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by Cariboo42
...
What I really want to understand is why a thread is blocking when it receives a message while it is creating a CDialog.
Again:
because a worker thread was not designed to handle thread messages. Just because it does not have message pump.
Victor Nijegorodov
-
June 9th, 2011, 07:33 AM
#6
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by VictorN
You could only PostThreadMessage is the thread you were posting to had the message pump. "Worker" thread has no message pump. Only MFC so called "UI" thread has.
I use CWinThread and everything works fine. I develop and use my application for about one month. I discovered this bug two days ago, when exiting the application, just after a panel creation.
Then, after log analysis and two days of work, I found out that this bug occurs only when a message is posted the same time the thread was creating a CDialog.
I think this can be due to a conflict when the message is added to the thread message pump and, at the same time, the CWinThread add the CDialog management to its message pump.
-
June 9th, 2011, 07:36 AM
#7
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by VictorN
Again:
because a worker thread was not designed to handle thread messages. Just because it does not have message pump.
Ok, we misunderstood. I use only CWinThread but I named this thread "working" thread because it has associated windows.
Also the "working" thread works fine. The problem lies in the "monitoring" thread.
-
June 9th, 2011, 07:40 AM
#8
Re: Problem: Creation of a modless CDialog in a thread.
Victor Nijegorodov
-
June 9th, 2011, 07:41 AM
#9
Re: Problem: Creation of a modless CDialog in a thread.
Sorry: ... it has NO associated windows.
-
June 9th, 2011, 07:46 AM
#10
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by VictorN
Did you read my post#3? Did you read the MSDN article AfxBeginThread?
How did you create your "monitoring" thread?
And again: why create a dialog in the secondary thread?
I created the thread using the CreateThread method, to have a message pump and then to be able to use PostThreadMessage.
My application mount/unmount modules and a need to create a thread for each module I mount. A module must be able to create dialog boxes.
-
June 9th, 2011, 08:15 AM
#11
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by Cariboo42
I created the thread using the CreateThread method, to have a message pump ...
Do you mean CWinThread::CreateThread or ::CreateThread API?
How exactly? Could you show your code?
Victor Nijegorodov
-
June 9th, 2011, 08:43 AM
#12
Re: Problem: Creation of a modless CDialog in a thread.
Code:
// Main thread: Creation of MonitorThread.
CMonitorThread* pMonitor = new CMonitorThread (); // Derived from CWinThread.
if ( pMonitor == NULL )
{
// Error management.
}
if ( pMonitor->CreateThread () == FALSE )
{
// Error management.
}
pMonitor->PostThreadMessage ( MSG_CreatePanel, 0, 0 );
#ifdef DO_BUG
Sleep ( 0 );
pMonitor->PostThreadMessage ( MSG_DestroyPanel, 0, 0 );
#endif
// Monitor thread: Hanlde the MSG_CreatePanel.
void CMonitorThread::OnCreatePanel ( WPARAM wParam, LPARAM lParam )
{
m_pPanel = new CMonotoringPanel ();
if ( m_pPanel == NULL )
{
// Error management.
}
if ( m_pPanel->Create ( IDD ) == FALSE )
{
// Error management.
}
m_pPanel->ShowWindow ( SW_SHOW );
}
DO_BUG not defined:
Works fine: The thread is created, the dialog box too.
DO_BUG defined:
Thread is created and both PostThreadMessage executed successfully (I checked the return value).
First message (MSG_CreatePanel) has been received, but m_pPanel->Create(IDD) blocks, as explaind in my original post.
-
June 9th, 2011, 09:21 AM
#13
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by Cariboo42
In fact, I develop an application with plug-ins and I decided to use Threads (and PostThreadMessages) for communication with my plug-ins. It also prevents the “main” thread to freeze due to time-consumer plug-ins.
IMO this is a bad design. Multi-threaded code is hard to debug and it's easy to introduce errors if a programmer doesn't know how to do MT programming correctly. When you have little or no control over some part of the code that will be executed by your program, you should try to prevent these problems. Thus, if the plug-ins need to create windows, let them do it in the main thread. If a plug-in has time-consuming operations, it should create its own worker thread to prevent the application from becoming non-responsive.
Originally Posted by Cariboo42
What I really want to understand is why a thread is blocking when it receives a message while it is creating a CDialog.
Maybe this will help: http://support.microsoft.com/kb/183116
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
June 9th, 2011, 10:02 AM
#14
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by D_Drmmr
Thanks. It helps to understand how dialog message pump works and the problems inherent to such design when using in threads. But this concerns essentially modal dialogs. IMO, it should work with modless dialogs, but what I also understand is that modless CDialog creation is not multi-thread safe regarding to PostThreadMessage.
Originally Posted by D_Drmmr
IMO this is a bad design. Multi-threaded code is hard to debug and it's easy to introduce errors
Indeed, it seems to be a bad design to create windows in separate threads. So I’ll redesign my application that way.
But I do not agree with the fact that MT programming is hard to debug. It’s like everything else: It requires being rigorous.
-
June 9th, 2011, 11:08 AM
#15
Re: Problem: Creation of a modless CDialog in a thread.
Originally Posted by Cariboo42
Thanks. It helps to understand how dialog message pump works and the problems inherent to such design when using in threads. But this concerns essentially modal dialogs. IMO, it should work with modless dialogs, but what I also understand is that modless CDialog creation is not multi-thread safe regarding to PostThreadMessage.
No, that page is not limited to modal dialogs. It talks about modal behavior and explicitly mentions moving or resizing the window as examples. I'm not sure, but it could be that dialog creation is modal behavior and therefore, the posted thread message is lost.
Originally Posted by Cariboo42
But I do not agree with the fact that MT programming is hard to debug. It’s like everything else: It requires being rigorous.
That's the first time I've heard anyone say debugging MT code is not hard. By its very nature MT-related bugs are not strictly reproducible, which by itself makes them hard to debug in my book. Also AFAIK, VS does not offer much support for debugging MT-related issues, unlike the tools offered to track memory leaks, iterator/bounds validation, memory values set by debug heap allocator, etc.
So, I'm curious what makes you say that MT programming is not hard to debug? Which tools/methods do you use?
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|