Can I have multiple GUI threads in MFC? - c++

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.

Related

How to avoid freezing the user interface in a loop (minimal example) [duplicate]

My first naive at updating my progress bar was to include the following lines in my loop which is doing the processing, making something like this:
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
//Added these lines but they don't do anything
ui->progressBar->setValue(numberProcessed++);
ui->progressBar->repaint();
}
I thought adding the repaint() would make the execution pause while it updated the GUI, but apparently it's not that simple. After looking at the questions:
QProgressBar Error
Progress bar is not showing progress
it looks like I'm going to have to put the data processing in a different thread and then connect a signal from the data processing thread to the GUI thread to update the progressbar. I'm rather inexperienced with GUIs and threads and I was wondering if anyone could just point me in the right direction, ie what Qt classes should I be looking at using for this. I'd guess I need a QThread object but I've been looking through the QProgressBar documentation but it doesn't bring up the topic of threading.
As #rjh and #Georg have pointed out, there are essentially two different options:
Force processing of events using QApplication::processEvents(), OR
Create a thread that emits signals that can be used to update the progress bar
If you're doing any non-trivial processing, I'd recommend moving the processing to a thread.
The most important thing to know about threads is that except for the main GUI thread (which you don't start nor create), you can never update the GUI directly from within a thread.
The last parameter of QObject::connect() is a Qt::ConnectionType enum that by default takes into consideration whether threads are involved.
Thus, you should be able to create a simple subclass of QThread that does the processing:
class DataProcessingThread : public QThread
{
public:
void run();
signals:
void percentageComplete(int);
};
void MyThread::run()
{
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
emit percentageCompleted(computePercentageCompleted());
}
}
And then somewhere in your GUI code:
DataProcessingThread dataProcessor(/*data*/);
connect(dataProcessor, SIGNAL(percentageCompleted(int)), progressBar, SLOT(setValue(int));
dataProcessor.start();
You need to call QApplication::processEvents() periodically inside your processing loop to let it handle UI events.
As Georg says, Qt is a single-threaded co-operative multitasking environment. You get full control of your process until you relinquish it voluntarily with processEvents() - until you do that, Qt can't update the UI elements, handle async HTTP requests, handle input, or pretty much anything else. It's up to you to make sure that stuff gets a timeslice while you're in a long processing loop.
You can create a sub-class of QThread that emits a signal progressChanged, which you connect to the QProgressBar.
connect() makes the connections auto connections per default. That means that the signal-slot-mechanism already takes care of the threading issues for you, so you don't need to worry about that.

PPL Task - Continuation in UI thread for desktop application

I would like to use a ppl task to do some work in the background, and, upon completion, show the result in a window. In my case the UI-framework is MFC. The structure would be:
using namespace concurrency;
create_task([] {
// this can be run in any thread, shouldn't be the UI thread
// do real work here
return 42;
}).then([](int n)
{
// this should be run on the UI thread
// ... open a MFC window to display results
});
The thing is, a non Windows Store app doesn't allow to specify the task_continuation_context. Instead, the runtime decides which context will be used (see task_continuation_context Class).
Can I rely on the runtime to reliably figure out that it needs to run the continuation on the UI thread? Is there a reasonable workaround to achieve what I want - without blocking the UI thread?
Update: Playing around showed that the runtime will not run the continuation on the UI thread. So, is it impossible?
What I did to solve this was to create a Dispatcher class and a message-only window, which is a member of the Dispatcher. The Dispatcher must be constructed (I used a singleton) from the main thread such that the main thread takes care of the messages which are sent to the message-only window. I can pass a std::function to my Dispatcher::ExecuteInMainThread function. The Dispatcher will then invoke SendMessage on the message-only window, passing in the pointer (unfortunately only a pointer will be possible) to the std::function. The only message handler I need in the message-only window will then invoke the function I passed in - within the main thread.
This Dispatcher can be used in the task continuation to execute a std::function in the main thread.

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

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.

Delegates and thread: CallbackContext parameter

I'm implementing threading in Metro mode, I got this example while Googling, but I don't understand CallbackContext . What's the use of this? This explains its use in MTA, but not clear to me. And I'm facing problem when I use CallbackContext as Any or Same. Something work with one but not with other! So first thing first I want to know what's the use of this?! PS: I'm new to WindowsRT programming and C++ too! Thanks!
auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
{
// Run the user callback.
try
{
func(data);
}
catch (...)
{
}
// Signal that the thread has completed.
SetEvent(completionEvent);
//CloseHandle(completionEvent);
}, CallbackContext::Same);
CallbackContext determines whether your delegate (in this case, a WorkItemHandler) aggregates the free-threaded marshaller. This will determine whether your delegate can be smuggled to another apartment (CallbackContext::Any), or if it must be called back to the originating apartment (CallbackContext::Same). Basically, it tells the person invoking your delegate whether it can be called directly regardless of apartment, or if they need to marshal back to the apartment it was created in.
For example, in a Windows Store Application, anything that modifies the UI needs to run on the UI thread (STA). Let's presume the method you're in is one that runs on the UI thread (such as an event callback, like a button click handler). Certain async calls like ThreadPool::RunAsync will run the passed-in delegate on a thread other than the UI thread (as the default for delegates is CallbackContext::Any). This is useful if you do not need to do anything on the UI thread, as it frees that thread up to continue pumping messages (and your app continues to feel performant).
However, if you do need to modify the UI or make a call back into the UI, and you attempt to do so from a non-UI thread, you will get an incorrect thread exception. By adding the parameter CallbackContext::Same you can force your delegate to run in the originating apartment (in this scenario, the STA) and thereby avoid the issue.
(You can also make a call back to the UI thread by using Dispatcher->RunAsync to invoke a further delegate to run on the STA. Whether it's better for your entire delegate to run on the STA or not depends on your scenario.)

Qt Programming and computations which take long time

I am new on Qt programming. I have to make some computations which take long time. I use an edit box and two button named as "start" and "stop". The edit box is used for the initialization. Start button starts the computation. While the computation is going on, I must be able to stop the computation whenever I want. But when I start the computation by clicking the start button. As expected, I cannot click any component on the window until the computation is completed.
I want to use the components (especially stop button) on the window normally while the computation is performing. But I am not good on the threads, I am looking for an easier method. Is there any simple solution?
There are a couple of options.
1. Subclass QRunnable
Subclass QRunnable and use QThreadPool to run it in a separate thread. To communicate with the UI, use signals. Example of this:
class LongTask: public QRunnable
{
void run()
{
// long running task
}
};
QThreadPool::globalInstance()->start(new LongTask);
Note that you don't need to worry about managing the thread or the lifetime of your QRunnable. For communicating, you can connect your custom signals before starting the QRunnable.
2. Use QtConcurrent::run
This is a different approach and might not suit your problem. Basically, the way it works is the following: you get a handle to the future return value of the long task. When you try to retrieve the return value, it will either give it to you immediately or wait for the task to finish if it hasn't already. Example:
QFuture<int> future = QtConcurrent::run(longProcessing, param1, param2);
// later, perhaps in a different function:
int result = future.result();
3. Subclass QThread
You probably don't need this, but it isn't hard either. This one is very similar to #1 but you need to manage the thread yourself. Example:
class MyThread : public QThread
{
public:
void run()
{
// long running task
}
};
QThread* thread = new MyThread(this); // this might be your UI or something in the QObject tree for easier resource management
thread.start();
Similarly to QRunnable, you can use signals to talk to the UI.
In your computation you can put QCoreApplication::processEvents(); so that GUI events also get processed. This will omit usage of threads.
You can have your computation occur in a different thread than your GUI. When the GUI recieves a signal that the stop button is pressed, you change a flag value which your computation thread periodically checks. When the flag is set, you can terminate the computation thread.
Either use threads (perhaps synchronizing them by sending messages on pipes to self), or use timer (with a 0 millisecond delays, this is how idle processing is done in Qt).