Basic QT Event handling / Threading questions? - multithreading

Greetings ,
I am new to QT (4.6) and have some basic questions regarding its event mechanism.I come from Swing background so I am trying to compare it with QT.
1) Does Event-processing-loop run in seperate thread? (like EventDispatch thread in Swing) ?
2) If we open several 'QMainWindow' do they run in several threads?
3) Whats the best way to run an intensive process in a seperate thread? (like SwingWorker in Swing ? )
4) If intesive-process runs in a seperate thread ,is it possible to call UI methods like update(),repaint() from that process?
thanks in advance.

1 Event loop running in the same thread
2 All UI elements are living in the same thread the one in which your main() function executed.
3 There are QThread class which allows you to have a thread with separate event loop. There is QRunable abstract class to be able to run repeating long running tasks in separate threads using QThreadPool.
4 update() and repaint() are slots and the best way to call them from separate thread is to use queued connection with a signal in your object which lives in separate thread (read QObject::connect documentation anbout connection types)
You can find all necessary information by reading documentation of classes I've mentioned.

Related

Can you create a separate QThread class and only call a specific function from it?

I have tried to read as much as I can about PyQt4's QThread and the idea of the worker thread. My question is, instead of building a QThread class to run everything in it from the def run(self): by the blahblah.start() command is there a way to create that individual thread class that has,say, 4 functions and you only call function 2 and then close that thread right after?
Subclassing QThread is a practice that is in general discouraged although often used. [see comment below]
In my opinion, this is a good example of how to use a thread in pyqt. You would create a Worker and a Thread, where the Worker is some general class of type QObject and the Thread is a QThread which you do not subclass. You'd then move the Worker to the Threat and start it.
self.worker = WorkerObject()
self.worker_thread = QtCore.QThread()
self.worker.moveToThread(self.worker_thread)
self.worker_thread.start()
Inside the Worker you can basically do whatever you want, it can have arbitrary many methods and so on.
The one big thing to keep in mind is that the Worker needs to be separate from the main loop. So the methods should not return anything that is used in the main loop (better not return anything at all) and the Worker's results should be collected using signals and slots.
self.button_start.clicked.connect(self.worker.startWork)
self.button_do_something_else.clicked.connect(self.worker.function2)
self.worker.signalStatus.connect(self.updateStatus)
Also make sure not to use any PyQt/GUI objects inside the worker, as this would also build a bridge between Worker and main loop through PyQt itself.

how to access a worker thread from UI thread?

I have a working thread running all along the runtime, who generates events.
I can handle those events inside the UI thread by using disp = Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher.
more precisely, I do the modifications to the UI by using disp->RunAsync(...) anywhere inside the working thread.
but I don't know how to do the inverted operation. I want to have some Async function inside the UI thread to perform operation (on some std::unique_ptr) in the working thread when I click on some button.
If I understand correctly you want to be able to run an async operation when a button is clicked, but on a specific thread to which you refer as your worker thread.
First - Since you want to use a resource in 2 threads you should not use unique_ptr and use shared_ptr since you share this resource between the two threads.
Second - if you don't necessarily have to run the action on a specific thread then you can simply use Windows::System::Threading::ThreadPool::RunAsync and capture the shared_ptr by value.
e.g:
namespace WST = Windows::System::Threading;
WST::ThreadPool::RunAsync(
ref new WST::WorkItemHandler(
[mySharedPtr](Windows::Foundation::IAsyncAction^ operation)
{
mySharedPtr->Foo();
}));
In case you have to run the operation on a specific thread then I assume you want to be able to append operations to an already running thread, otherwise you are creating a thread and you can use the above example.
So in order to append operations to an already running thread, that thread must have the functionality of getting a new operations and then running those operations in a synchronous order. This functionality is basically what the Dispatcher provides. This is what an Event Loop is, also called: message dispatcher, message loop, message pump, or run loop. Also you can find information by reading on the Recator\Proactor design pattern.
This CodeProject page shows one way of implementing the pattern, and you can use Winrt component to make it better \ more conveniant \ more familiar

Does timer need mutex

I use timer in my program:
timer = new Qtimer(); connect(timer, SIGNAL(timeout()), this, SLOT(readData())); timer.start(1000);
And there is also other slots which may be triggered by UI interation:
/*SLOT FUNCTION*/ on_pushbutton_triggered(){..../*write data*/...}.
(the code is written in qt, but I think it's a common question)
So I worry about the potential problem: may readData() reads wrong data while on_pushbutton_triggereed() is writting data?
I am not so familiar with how the timer really work behind the screen: is it in the same thread with my program?
Will readData() and on_pushbutton_triggereed() be called, executed, finished serially and have no mutex problem(that is: I have to use lock() and unlock())? Thank you for reading! I really hope for your hints!
Qt is using an event loop to implement concurrent activity in general and QTimer in particular within a single thread.
The event providers (QTimer in this case) are producing events and publish them to the event loop. Then they are processed according to their priority and order of publishing. This approach doesn't require any synchronization as there is only one section of code executed at the time, so it's safe to access data.
On Unix-like systems ps -eLf command will show information about all processes (PID column in the output) and their threads (LWP column). NLWP column shows how many threads particular process has.

QPointer in multi-threaded programs

According to http://doc.qt.io/qt-5/qpointer.html, QPointer is very useful. But I found it could be inefficient in the following context:
If I want to show label for three times or do something else, I have to use
if(label) label->show1();
if(label) label->show2();
if(label) label->show3();
instead of
if(label) { label->show1();label->show2();label->show3(); }
just because label might be destroyed in another thread after label->show1(); or label->show2();.
Is there a beautiful way other than three ifs to get the same functionality?
Another question is, when label is destroyed after if(label), is if(label) label->show1(); still wrong?
I don't have experience in multi-threaded programs. Any help is appreciated. ;)
I think the only safe way to do it is to make sure you only access your QWidgets from within the main/GUI thread (that is, the thread that is running Qt's event loop, inside QApplication::exec()).
If you have code that is running within a different thread, and that code wants the QLabels to be shown/hidden/whatever, then that code needs to create a QEvent object (or a subclass thereof) and call qApp->postEvent() to send that object to the main thread. Then when the Qt event loop picks up and handles that QEvent in the main thread, that is the point at which your code can safely do things to the QLabels.
Alternatively (and perhaps more simply), your thread's code could emit a cross-thread signal (as described here) and let Qt handle the event-posting internally. That might be better for your purpose.
Neither of your approaches is thread-safe. It's possible that your first thread will execute the if statement, then the other thread will delete your label, and then you will be inside of your if statement and crash.
Qt provides a number of thread synchronization constructs, you'll probably want to start with QMutex and learn more about thread-safety before you continue working on this program.
Using a mutex would make your function would look something like this:
mutex.lock();
label1->show();
label2->show();
label3->show();
mutex.unlock()
As long as your other thread is using locking that same mutex object then it will prevented from deleting your labels while you're showing them.

How do you call the GUI thread in Silverlight from the BackgroundWorker method?

I am using a BackgroundWorker thread to do some work outside of the GUI thread in Silverlight 4. I would like to update widgets in the GUI context from the background thread, but have read warnings about doing so from Microsoft documentation. I understand that communicating from one thread to another throws an exception as only the GUI thread can update widgets, but isn't BeginInvoke provided for this:
// BackgroundWorker thread code...
Widget.Dispatcher.BeginInvoke(() => Status.Text = "Hello");
However, I am getting some unpredictable results in my worker code.
What is the proper way to cross communicate with the GUI thread ? Is it by passing a results collection out of the RunWorkerCompleted method ?
Thanks,
Scott
You don't call the GUI code directly.
You must fire and event to which the UI thread subscribes. It then does the marshalling necessary to update the UI safely.
There are plenty of questions (and answers) on this. See some of the "Related" questions in the right hand side bar.

Resources