Displaying window from ui-thread sometimes blocks the main ui-thread - c++

I am not an MFC expert, and definately not a multithread expert but still, I want to understand this strange behavior. At some places when I create an MFC ui thread in my application it is started and can display a messagebox no problem, with the main ui thread blocked. However sometimes if I create the thread, then the thread execution stops until the main ui thread non-blocked again.
Of course the situation is made up. The main ui thread's blocking, symbolizes some kind of synchronisation, while the ui thread's messagebox symbolizes some more complex ui dialog.
This is more of a theoretical question. I am primary interested in the reason why this could happen? Here is an example :
class MessageBoxThread : public CWinThread
{
DECLARE_DYNCREATE( MessageBoxThread );
public:
virtual BOOL InitInstance()
{
CWinThread::InitInstance();
AfxMessageBox(_T("Some text"));
return TRUE;
}
};
IMPLEMENT_DYNCREATE( MessageBoxThread , CWinThread );
void testing()
{
MessageBoxThread* pMessageBoxThread = new MessageBoxThread ();
pMessageBoxThread->CreateThread();
Sleep(10000);
AfxMessageBox(_T("It Worked!"));
}
So in terms of the example, if I put 'testing' function into CWinApp::InitInstance it is working as expected (showing 'Some text' first then after 10 sec showing 'It Worked!'). However if I put it into a random place deep inside my application, it might happen that the two messageboxes appear at the same time after the 10 sec sleep. What could cause such behavior?

I am not an MFC fan, but knowing Win32 I can see what is happening. By putting it "deep" you probably mean calling the testing() function in some window message processing code - a code that runs on the main UI thread and processes pumped messages. So you are putting your UI thread to sleep which in this case is similar to what a message box or a modal dialog would do. So, your message pump (implemented in CWinApp I think) is blocked by this Sleep() waiting you to complete processing the message in response to which your code is executed (does not matter what message).

Okay, I finally found the answer. When someone creates a ui thread, that person must initialize the m_pMainWnd member which contains the ui threads base window. If you fail to do so, the framework will use the application provided main window, which is the one in the main ui thread. Since that one is blocked because of the Sleep() method, the other ui thread will only respond when the main thread is not blocked.

Related

Access the Winform control that started a thread

I've got a WinForm project which uses a PageControl and PageTabs. Say there are two PageTabs, each with their own UserControl object. If one UserControl starts a Thread() which is meant to loop endlessly and access a TextBox on the UserControl that started it, how does that thread's process access the correct UserControl.
More specifically:
The GUI.h has two PageTabs, each with their own UserControl object.
The first tab has a ReceiveButton which starts a thread. That thread does a lot of work on a loop and updates the TextBox.
The second tab is essentially the same, but has it's own ReceiveButton and TextBox. This button also starts a thread and is supposed to update this TextBox.
I'm having a tough time figuring out how to make each thread access/update it's own respective TextBox.
Here's sort of the chain of code my UserControl follows:
//MyUserControl.h
void ContinueNormally(void);
System::Void buttonReceive_Click(System::Object^ sender, System::EventArgs^ e)
{
this->myThread = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this, &MyUserControl::ContinueNormally));
this->myThread->Start();
}
//GUI.h
#include "MyUserControl.h"
void BufferRecieveLoop()
{
while (true)
{
//receive from multicast
incoming.Process(buffer, bytes_read, endian); //this is the method in the other .h file
}
}
void MyUserControl::ContinueNormally()
{
//setup
BufferRecieveLoop();
//cleanup
}
//EntityStateProcessorPdu.h
#include "MyUserControl.h"
void EntityStatePduProcessor::Process(const DIS::Pdu& packet)
{
//do stuff
///Below are attempts at accessing the correct textbox, all in vain :(
//GUI_Example_Receive::Globals::gui->SetConsoleTextBoxText(sysStr);
//GUI_Example_Receive::Globals::gui->Controls->Find("myUserControl", true)[0]->Controls->Find("")
//GUI_Example_Receive::MyUserControl::SetTextBoxConsoleText(sysStr);
}
I should also note that this works just fine with one UserControl, or one PageTab. I'm Invoking correctly to get the UI thread to do the updating.
In Win32 (and pretty much any OS GUI that I know of) only allows one "thread" to access the GUI. This is normally known as the "GUI Thread".
The "GUI Thread" is the thread that runs the Win32 message pump.
Normally what you do is post your own "custom" messages that will be run in the GUI thread and you update your GUI controls from there.
I don't know the C++ GUI library you are using but it will most likely provide some sort of utility for post messages or code to be run on the GUI thread.
In Windows Forms every controls has a method Invoke, that it does what you search:
calls a delegate in the same thread that creates the control.

Progress Bar doesn't move

I need such logic:
ShowProgressBar();
Sleep(1000); //---> do here some work
HideProgressBar();
MessageBoxW(_T("Wait"), _T("Title"), MB_OK);
ShowProgressBar();
Sleep(1000); //---> do here some work
HideProgressBar();
I call this code in separate thread (not main GUI thread). I got normal dialog window but it's progress bar is immobilized:
Then:
And then:
This is ShowProgressBar function:
progressBarWindow = new Progress(this);
if (!progressBarWindow->Create(IDD_PROGRESSBAR, this))
{
AfxMessageBox(TEXT("BAD PROGRESS BAR"));
return;
}
if(!progressBarWindow->ShowWindow(SW_SHOWNA))
{
AfxMessageBox(TEXT("BAD PROGRESS BAR"));
return;
}
this->BeginModalState();
This is HideProgressBar implementation:
progressBarWindow->EndDialog(0);
this->EndModalState();
Progress - is a class of Progress Bar dialog window. It is absolutely standart, has progress bar element with marque setting:
m_ProgressBar.SetMarquee(TRUE, 10)
in OnInitDialog function
Windows have thread affinity.
You’re calling progressBarWindow->Create() on a background thread. The progress bar now lives in your background thread, and expects the thread to have a message pump.
It doesn’t matter it’s parent window belongs to another thread, Windows is OK doing multi-threaded GUI. However you’re not OK. You’re sleeping with Sleep(1000), so the thread ain’t processing windows messages. I think that’s why no GUI updates in your app.
For most applications, the right way to do threading — do all the GUI in the main thread. Even progress bars logically related to the background threads should still be created in the main GUI thread.
To fix, create all your GUI in the main GUI thread, and only use your separate thread for computations, or IO, or whatever else your work is.
P.S. If your next question going to be “But how to notify the GUI thread when my background thread needs to change progress, or completes its job?” — one method is custom windows messages.
For example, you can send WM_USER + 11 to some window (e.g. to your Progress dialog) when your thread finishes the processing, and WM_USER + 12 when your thread needs to update the progress bar position, passing progress position in lParam or wParam. The message handler will be called in the main thread, where you can update progress, or close the progress popup, or do anything else with your GUI.

Can I have multiple GUI threads in MFC?

I have a large MFC based application that includes some potentially very slow tasks in the main thread. This can give the appearance that the application has hung when it is actually working its way through a long task. From a usability point of view, I'd like to be giving the user some more feedback on progress, and have an option to abort the task in a clean manner. While hiving the long tasks off into separate threads would be a better long term solution, I'm thinking a pragmatic short term solution is create a new GUI thread encapsulated in its own object complete with dialog including progress bar and cancel button, used in a similar manner to a CWait object. The main thread monitors the cancel status via an IsCancelled method, and finishes via a throw when required.
Is this a reasonable approach, and if so is there some MFC code out there already that I can use, or should I roll my own? First sketch looks like this
class CProgressThread : public CWinThread
{
public:
CProgressThread(int ProgressMax);
~CProgressThread()
void SetProgress(int Progress);
BOOL IsCancelled();
private:
CProgressDialog *theDialog;
}
void MySlowTask()
{
CProgressThread PT(MaxProgress);
try
{
{
{ // deep in the depths of my slow task
PT.SetProgress(Progress);
if (PT.IsCancelled())
throw new CUserHasHadEnough;
}
}
}
catch (CUserHasHadEnough *pUserHasHadEnough)
{
// Clean-up
}
}
As a rule, I tend to have one GUI thread and many worker threads, but this approach could possibly save me a bunch of refactoring and testing. Any serious potential pitfalls?
Short answer, Yes, you can have multiple GUI thread in MFC. But you can't access the GUI component directly other than the created thread. The reason is because the Win32 under the MFC stores the GUI handler per thread based. It means the handler in one thread isn't visible to another thread. If you jump to the CWinThread class source code, you can find a handler map attribute there.
Windows (MFC) doesn't has hard difference between the worker thread & GUI thread. Any thread can be changed to GUI thread once they create the message queue, which is created after the first call related to the message, such as GetMessage().
In your above code, if the progress bar is created in one thread and MySlowWork() is called in another thread. You can only use the CProgressThread attributes without touch the Win32 GUI related functions, such as close, setText, SetProgress... since they all need the GUI handler. If you do call those function, the error will be can't find the specified window since that handler isn't in the thread handler mapping.
If you do need change the GUI, you need send the message to that progress bar owner thread. Let that thread handles the message by itself (message handler) through the PostThreadMessage, refer to MSDN for detail.

Callback implementation using Windows message loop

I have C++ library (Win32 Console) where I have implemented an asynchronous function using a timer. The asynchronous method returns device information.
I have created a separate thread, "Timer Thread", to create a hidden window and then I call SetTimer() and then the implemented message loop.
When the timer expires, it enables a callback.
When I use the library in a console application, it is working fine.
In an MFC application I am doing a post message to update the user interface when the callback triggers. The post message is not working.
If I remove the message loop in the library, it is working fine in the MFC application.
I came to conclusion that:
I guess the problem is due to two message loops, one MFC (main thread) and the TimerThread message loop. So when the callback is called and the subsequent PostMessage results in the TimerThread message loop and not reported in the MFC (main thread) message loop.
If I remove the TimerThread message loop then it works fine in the MFC application, but it fails to work in the console application.
How do I overcome this problem?
class IDeviceEnumerationCallback
{
public:
virtual void onDeviceDiscovered(DeviceInfo* pDeviceInfo,unsigned short nNoOfDevice) = 0;
};
class IDeviceDiscovery
{
public:
virtual int InitialiseDiscovery(IDeviceEnumerationCallback*) = 0;
virtual void UnInitialiseDiscovery() = 0;
virtual int EnumerateDevice() = 0;
};
class CDeviceDiscovery:IDeviceDiscovery
{
//Implementation
}
In the MFC/console application I am implementing IDeviceEnumerationCallback to get a callback.
I am using Bonjour API to enumerate the device and all the methods in Bonjour API are callbacks.
I am wating for some time interval to enumerate a device using Bonjour API and then say after 400 ms I am calling a callback to return the result. In the MFC application when the callback is called, I am doing a PostMessage() to update the user interface.
Earlier I tried without Windows message pump. I had a SetTimer function, and it is working with the MFC application, but for the console application, the callback never gets called, so I implemented a message pump here. Now it is not working for MFC application.
First, there's no reason to do what you did: creating a separate threads, then creating a window in it, set the window timer, run the message loop, respond to the WM_TIMER message and invoke the callback.
If you create "your own" thread - you don't actually need all this. You could just implement a simple loop with either Sleep (or WaitForXXXX if you want an abort option), and invoke your callback.
Usually one creates a hidden window with a timer to avoid creating an additional thread. That is, within a thread that operates GUI (and hence - runs the message loop) you create a window, and it will be served by the message loop. Actually this is would you could do in your MFC app.
However, as you said, you want a generic code for both MFC and console apps.
In MFC application I am doing post message to update UI when the
callback triggers.the post message is Not wokring.
What exactly do you mean by "diung post message"? The message should be posted either to a specific window, or to the thread. In the first case it's dispatched to the window procedure, and in the second case the message loop implementation is responsible for handling the message.
If you post your message to a specific window - how do you get its handle (HWND)? Is it your app's main window (AfxGetMainWnd)? What does your thread start working, after the MFC has created the main window, or earlier?
I ask all those question because you seem to be a newbie (no offences), and those are typical mistakes.
The problem is that you should not be creating a hidden window and using SetTimer instead you should be using the MFC worker thread functionality for background work.
//You create a thread like so.
// you need a CMyObject only if you need to pass any information
//to the thread function.
CMyObject *pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
//This function will be run in separate thread
UINT MyThreadProc( LPVOID pParam )
{
//The parameter that was passed to this function
CMyObject* pObject = (CMyObject*)pParam;
while( 1 )
{
//add your code to do stuff.
Sleep(5000); //or whatever your SetTimer interval was
}
return 0; // thread completed successfully
}

Application wide periodic tasks with Dialog Based MFC application

In Single Document Interface (SDI) or Multiple Document Interface (MDI) MFC application, I created an application wide timer in the View. The timer will tick as long as the application is running and trigger some periodic actions.
How can I do the same with Dialog Based MFC application?
Should I create Thread's Timer (SetTimer with NULL HWND) and pass a callback function to it?
Should I create worker threads? My experience with other projects was when I tried to display some feedback GUI from non-GUI/worker threads, I need to roll out my own "delegate"/command pattern and a "delegate invoker"/command invoker. The worker thread will send message (I think using message is safer than direct function call when dealing across thread-boundary, CMIIW) to the UI-thread. and the UI-thread will be the "delegate"/command invoker. Failing to do this and to make sure that the windows/dialogs have the correct parent will result in bizzare behaviors such as the Application suddenly disappears to the background; Window/Dialog that is shown behind the current window/dialog and causing the current window to be unresponsive/unclickable. Probably I was doing something wrong but there were so much problems when dealing with threads.
Are there best practices for this?
A timer works as well in a dialog-based application as an SDI or MDI app. OTOH, timers are (mostly) a leftover from 16-bit Windows. If you want to do things periodically, a worker thread is usually a better way to do it (and yes, Windows Mobile supports multiple threads).
Edit: in a dialog-based application, the main dialog exists for (essentially) the entire life of the application. Unless you really need the timer during the milliseconds between application startup and dialog creation or dialog destruction and application exit, just attach it to the dialog. Otherwise, you can attach it to the main window -- which MFC creates and destroys, even though it's never displayed.
If you use the MFC Wizard to create the Dialog based app, you probably have a hidden view window as well as a dialog window. The view window creates the dialog with DoModal(), which runs the dialog in the same thread, effectively suspending the view window.
While the dialog is open, the view window will not process any events. So, if the view window owns the timer, it will not process the timer events.
The simplest solution is to create the timer in the dialog and let the dialog handle the timer messages.
IMO, use the Timer if it solves the problem. As you've mentioned a Worker Thread interacting with the UI, in MFC, can be more trouble than its worth sometimes.
If the problem is simple enough for a timer to suffice, thats what i'd use (Remember KISS)
SetTimer does not have to be handed a window to work, it can call a callback method.
You can use that in your application - declare in your CWinApp (or anywhere really)
static void CALLBACK OnTimer(HWND, UINT, UINT, DWORD);
Then in the InitInstance call SetTimer(0, [eventid], [time period], OnTimer);
In OnTimer you can get back to the CWinApp instance via AfxGetApp() or theApp since there is only one.
Second attempt: my previous answer was dne in a hurry and was not correct.
Your basic vanilla MFC Dialog app only uses one thread. The main thread starts with a class derived from CWinApp. In the InitInstance() method it launches the dialog using CDialog::DoModal(). This function doesn't return until the dialog is closed.
While the dialog is running, the CWinApp class does not process any messages, so won't see a WM_TIMER.
There are many ways around this.
Let the first dialog own the timer and make all other dialogs children of it. This might be OK, depending on your dialog requirements, but it might be too restrictive.
Launch the first Dialog as modeless, i.e. use Create() instead of DoModal(). Create() returns straight away (putting the Dialog into a different thread). You can then create a message loop in the CWinApp class and process timers there. You'll have to use thread timers instead of window timers as the CWinApp class doesn't have a window. (or you could create a hidden window if that is more convenient).
You can hack the dialog's mesage loop and make it pass messages to the CWinApp class' message handler. That is quite complex and not for the faint hearted.
You can create a dedicated timer thread. You'd probably do that from the CWinApp class before it creates the dialog, but other strategies are possible.
Do any of those schemes sound like they fit your needs? If not, maybe you can explain your needs more fully and we might be able to come up with something appropriate.