QThread Vs QFuture - qt

Which is more appropriate: QThread or QFuture ?
I'm trying to pass a QNetWorkAccessManager in a QThread but it causes an error with the parent and child thread :/
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xc996cf8), parent's thread is QThread(0xaba48d8), current thread is Citizen(0xca7ae08)
m_networkManger = new QNetworkAccessManager(this);
m_thread = new QThread();
m_data = new LoadData(m_labelsList, m_parserType, argUrl, m_networkManger);
m_data->moveToThread(m_thread);
connect(m_thread, SIGNAL(started()), m_data, SLOT(process()));
connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
m_thread->start();
Could using QFuture solve the problem?

My first thought was why do you want to move the networkManager to a different thread anyway?
Anyhow, the problem you see is that when you move an object to a new thread, it moves the object and its children.
You create m_networkManager and pass 'this' to it, making that object its parent. Whatever that object is, it will be residing on the original thread. You can't move a child object to a different thread from its parent.
Therefore, remove the parent object 'this' when creating the QNetworkAccessManager.
m_networkManger = new QNetworkAccessManager;
Ensure you handle deleting of the networkManager, now that it is no longer parented.

The object which is moved to other thread must not have a parent. Qt is designed in such way that whole object tree must be in one thread (object is moved to other thread with all its children).
If object has a parent it is moveToThread will fail (do nothing only prints error in logs).
QFuture doesn't change anything in this case.
Note that you can run object methods in different thread then object belongs to. If objects belong to some thread it means that connected slots of this object will tend to be called from this thread (only if connection type was Qt::DirectConnection slot can be invoked from different thread).

Related

moveToThread(qApp->thread()) and signal-slot

If I understand correctly, slots will always occur in the main thread.
So what is the difference between using the signal-slot system and moveToThread(qApp->thread())?
Your understanding is incorrect.
Each thread has its own event queue, so when a signal is emitted, if the connection is queued (not direct), it will be added to the event queue matching the thread affinity of the object.
For example: -
Let's assume that we have 2 objects; object1 running on the main thread and object2, which has been moved to a new thread.
connect(object1, &SomeObject::signal1, object2, &SomeOtherObject::signal2);
When object1 emits signal1, an event is posted to the new thread; the thread to which object2 was moved.
When the new thread processes its event loop and the event for signal1 it will execute object2's slot, signal2. This is not on the main thread.
Each QObject tree can be assigned to a specified thread. moveToThread means move tree of objects (for given root object) to that thread.
That doesn't mean that that all code of the QObject is assigned to that thread. It means that any slot invoked by queued connection (not direct connection) will be invoked in given thread. Read carefully documentation of QObject::connect and Qt::ConnectionType.
Except for Qt::DirectConnection, all connections use the owning thread of the receiving object to deliver the signal. All arguments are packed and sent to the receiver's event queue. When the receiving thread's event loop gains control it will unpack the arguments and invoke the slot.
Note that I wrote above about a tree of objects. You can't move an object to a different thread if it has a parent. And you can't reparent an object to one that belongs in a different thread.
By default objects are assigned to thread which created them (if they do not have a parent). So it doesn't have to be main thread.
Thread a,b,c;
a created b, b created c;
connect(a, &QThread::finished, a, &QObject::deleteLater);
connect(b, &QThread::finished, b, &QObject::deleteLater);
connect(c, &QThread::finished, c, &QObject::deleteLater);
I do some experiment, found that if b had finished faster than c, c would not be deleted; But can do that:
b->moveObject(a); //then b would be deleted again.

QThread and QML Locking Up

I have a class, audio_engine_interface, and in main.cpp, I add it to the QML thing.
viewer.rootContext()->setContextProperty("engine", engine);
In audio_engine_interface, I have a audio_engine class, which is computationally intensive—it needs to run on its own thread.
void audio_engine_interface::play()
{
QThread thread;
thread.start();
engine->moveToThread(&thread);
engine->play(); // Will use 100% of CPU
}
However, when I do this, the whole QML thread locks up, meaning I can't pause (pretty important). Am I missing something?
EDIT:
This thread won't mess up anything or access objects from other places. However, it does have a pause function that will need to be called at some point. For what it's worth, the engine is doing pitch shifting.
This is a problem: -
Qthread thread;
Creating a QThread object like this is creating it on the stack. When the function ends, the object will go out of scope and delete the QThread object.
You need to dynamically allocate the object on the heap: -
QThread* thread = new QThread;
Then remember to delete the thread, or set it to delete itself: -
//Qt 5 connect syntax
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
You should also be aware of thread affinity (the thread which an object is running on). I suggest reading this article on how to use QThread properly.
You have so many problems.
when you move to thread your object must not have a parent
your thread object is local variable so it will day immediately when udio_engine_interface::play() end execution
you are invoking you engine->play(); method directly and this means that it will be executed in current thread.
moveToThread means that slots invked by signals connected using default 5th parameter (Qt::AutoConnection) will be queued in event loop of given thread.
The easiest way to fix it is use QtConcurrent:
void audio_engine_interface::play()
{
QtConcurrent::run(engine, &EngineClass::play);
}
Depending what your engine does you should make it thread safe (use mutex locks an so on), without details it is hard to tell, what exactly you should do.

QTimer timeout signal not invoking slot when run on a different thread

I have a subclass of QObject referred to as myObject, which has a QTimer data member allocated on the heap in the constructor. myObject also has a slot which is connected to the QTimer timeout() signal in the constructor. I refer to the pointer of myObject as myObject_ptr.
I want to run myObject on a different thread from the main thread. Following the relatively new recommendations, I DO NOT subclass QThread. In the main thread, I use myObject as follows:
QThread *thread = new QThread(this);
myObject_ptr->moveToThread(thread);
connect(myObject_ptr, SIGNAL(destroyed(), thread, SLOT(quit())); //thread not needed if no object
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); //to avoid memory leak
connect(thread, SIGNAL(terminated()), thread, SLOT(deleteLater())); //to avoid memory leak
thread->start();
The main thread invokes a function of myObject_ptr which in turn starts the QTimer data member. When it times out, nothing happens, but I expect the slot of myObject to which the timer's timeout() signal is connected to be invoked. What is the problem? How do you make this work. It works flawlessly if myObject is run on the same thread where it was created i.e. main thread.
From all the readings I've done, I think the new thread I am creating might not be processing events because it doesn't have it's own event loop. I also read documentation/articles contrary to that, saying that when the thread starts, the run() function calls exec() and you have an event loop.
Could someone help me please?
I could probably get it to work correctly if I subclass QThread, but based on current recommendations, I would prefer to avoid doing that.
Thank you in advance.
I solved my problem!! In the constructor of MyObject, the timer is allocated on the heap as follows:
timer_ptr = new QTimer(this);
but to work correctly, it should be:
timer_ptr = new QTimer(0);
and in the destructor, delete the object manually:
timer_ptr->deleteLater();
I guess when they say can't move an object with a parent to a thread, they really do mean ALL objects, including data members of the object actually being moved to the new thread.
Happy coding.

QObject.moveToThread(thread) if thread is a child of that object

I wanted to create QObject (object) with the child QThread (thread) with that object as parent (for keeping thread alive while object is alive) and make object.moveToThread(thread) but signal to start the thread isn't working in this case.
Simply:
object owns thread
object moves to thread
signal starting thread isn't working
What's going on?
[Edit]: Throwing away my initial answer due to the comments
Maybe do it like the following:
Create the Object
Create the Thread, but don't assign a parent to it
Connect the Thread's finished() signal to its deleteLater() slot as usual
Connect the Object's deleted() signal to the thread's stop() slot
Then, when you delete the Object, it will emit deleted() which will stop the thread. The thread will emit finished() which will call its deleteLater() slot.

Ways to create a QDialog outside the main thread

I am trying to create a client application in QT which requires both threads for processing and a variable amount of window instances. But I am having a hard time trying to figure out how to create a new window inside one of the processing thread. I understand that all ui elements must be created in the same thread as the QApplication class, but I need to be able to instantiate, or at least have a reference to a QDialog in another thread.
Communicating between the thread and QDialog can be done using signals, I am not worried about this, but actually creating the window is another matter. I could use signals to tell the main thread to create an instance to the window, and then retrieve the pointer to it somehow, but to me that seems a bit to complicated and ugly. Is there a better way to accomplish such a task? To create a QDialog outside the main thread were the QApplication class exists?
Edit : I have tried the Q_INVOKABLE method but it does not work across threads. I have created a view factory class which can create a QDialog of a type I specify and returns a pointer to it. This class has been instantiated in the main GUI thread and a reference to this class is sent to any worker threads. The problem is that, when a thread invokes the create method from the factory using Qt::BlockingQueuedConnection, the invoke method fails. If I change it to Qt::DirectConnection, the invoke method calls the right create method but in the current thread as the worker thread.
My main function looks like this :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ViewFactory vFactory;
vFactory.registerCreator(Util::W_CONNECT, new ConnectWindow::ConnectCreator());
ClientApp app;
if(!app.Initialize(&vFactory))
return 0;
app.start();
a.exec();
.............................
}
And my run function from the ClientApp thread looks something like this :
void ClientApp::run()
{
QDialog * tmp = NULL;
QMetaObject::invokeMethod(this->_vFactory, "create", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QDialog*, tmp), Q_ARG(int, 0));
}
Like I said, the invokeMothod will not fail if I change the connection type to Qt::DirectConnection, so the params are not the problem, but rather calling the method across a separate worker thread.
You can only do Gui stuff in the gui thread. The obvious solution is for the worker thread to send a message to the gui thread = a signal in Qt terms.
If a worker thread needs to ask a question it should send a message to the gui thread and then block until it gets a signal back.
AFAIK, signals (or just a dynamically callable method, using Q_INVOKABLE) or an event is the way to go.
Note that, using QMetaObject::invokeMethod() (with Qt::BlockedConnection), you can call a function safely across threads and get a return value back without too much coding.
It seems like QObject::moveToThread can solve this problem. This function moves event processing loop to another thread.
Example from Qt documentation:
myObject->moveToThread(QApplication::instance()->thread());

Resources