Is this the correct way to use a QThread? - c++

I am looking at some github projects, where one of them did the UDPlink in the following way,
first it subclass QThread to create a class UDPLink:public QThread
and its constructor and deconstructor is like:
UDPLink::UDPLink(UDPConfiguration* config)
: _socket(NULL)
, _connectState(false)
{
Q_ASSERT(config != NULL);
_config = config;
_config->setLink(this);
// We're doing it wrong - because the Qt folks got the API wrong:
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
moveToThread(this);
// Set unique ID and add link to the list of links
_id = getNextLinkId();
qDebug() << "UDP Created " << _config->name();
}
UDPLink::~UDPLink()
{
// Disconnect link from configuration
_config->setLink(NULL);
_disconnect();
// Tell the thread to exit
quit();
// Wait for it to exit
wait();
this->deleteLater();
}
Though the code did compile and work, but I wonder whether this way of using a QThread would be correct?

The Qt docs for QThread describe the two ways threading can be done with QThread. Sub-classing QThread was the only way to use QThread initially. To use QThread in this manner, override the run method, which is the QThread method that runs on a new thread. QThread should be thought of as a thread manager, not an object that runs on a separate thread itself. From the docs:
It is important to remember that a QThread instance lives in the old
thread that instantiated it, not in the new thread that calls run().
This means that all of QThread's queued slots will execute in the old
thread. Thus, a developer who wishes to invoke slots in the new thread
must use the worker-object approach; new slots should not be
implemented directly into a subclassed QThread.
When subclassing QThread, keep in mind that the constructor executes
in the old thread while run() executes in the new thread. If a member
variable is accessed from both functions, then the variable is
accessed from two different threads. Check that it is safe to do so.
QThread documentation page
It's because QThread is a thread manager class that a solution for moving objects to threads was created. The comment in the code you provided makes a statement about this change, since that article states that moveToThread(this) isn't a good practice.
Creating an object and moving it to a thread and sub-classing QThread are both valid approaches to threading with Qt, as the documentation now states clearly. There is a benefit to using the worker-object approach, if you desire to use signal/slot connections across thread boundaries: a worker object will have its slots available on the thread it is moved to.

As Qt developer recommended, Code you mentioned is not correct way to use QThread.
Recommended way is suggested here.
Sample code from Post.
Producer producer;
Consumer consumer;
producer.connect(&consumer, SIGNAL(consumed()), SLOT(produce()));
consumer.connect(&producer, SIGNAL(produced(QByteArray *)), SLOT(consume(QByteArray *)));
// they both get their own thread
QThread producerThread;
producer.moveToThread(&producerThread);
QThread consumerThread;
consumer.moveToThread(&consumerThread);
// go!
producerThread.start();
consumerThread.start();

Related

Invoking a function on a QThread that is already running

I have seen a lot of examples on the internet (and the Qt documentation) where to use QThread, a subclass of the class is made and then a worker object is moved to that thread. Then essentially the QThread::started() signal is connected to some slot of the worker class object to run a certain function.
Now I would like to do the same in my project, the difference being I would like to move my worker class to a thread that is already running and then call some function on that thread. To achieve this I came up with a slight hack like in the code below, where I use the QTimer class to invoke a public slot in my worker class.
QThread myThread;
myThread.setObjectName("myThread");
myThread.start();
Worker worker;
worker.moveToThread(&myThread);
QTimer::singleShot(0, &worker, [&worker](){
worker.doStuff(5);
});
Is there a more idiomatic way to achieve the same thing?
If "doStuff" is a slot then you can use QMetaObject::invokeMethod:
QMetaObject::invokeMethod(&worker, "doStuff", Qt::QueuedConnection, Q_ARG(int, 5));

Change affinity of an Object from a QThread to Main GUI Thread

I have a Qt GUI application which contains some classes and a main. For one of the computationally heavy writing operation i created a a QThreadas a class member. Something like this:
//class members
std::unique_ptr<QThread> m_savingThread;
std::unique_ptr<DiffClass> m_controller;
connect(this, &SomeClass::saveAll, m_controller.get(), &DiffClass::saveToAll, Qt::QueuedConnection);
connect(m_controller.get(), &DiffClass::done, m_savingThread.get(), &QThread::quit);
void SomeClass::saveToFile()
{
//Saving thread
qDebug() << "From main thread:" << QThread::currentThreadId();
m_controller->moveToThread(m_savingThread.get());
m_savingThread->start();
qRegisterMetaType<std::string>("std::string");
emit saveAll(someString);
}
The above code works fine. But i need the m_controller object back to the main GUI thread once the saving operation is finished. I could find something similar
here. Briefly, it states that since QThread can only "push" the object into a thread, i need to push it again into the main thread from the current worker thread.
void DiffClass::saveToAll(someString)
{
qDebug() << "From worker thread:" << QThread::currentThreadId();
/*saving operation*/
moveToThread(QApplication::instance()->thread()); //Error QCoreApplication has no member thread()
emit done();
}
Is there a way to change the affinity of the object back to the main thread?
EDIT 1: My connect to saveToAll is a QueuedConnection.
First and foremost, why would you want to switch thread affinity back and forth? There doesn't seem to be a practical side to this.
Other than that, it should be possible to change it to another threat, the condition is that the object has no parent and the moveToThread() is invoked from the current affinity thread.
You can use QMetaObject::invokeMethod() with Qt::QueuedConnection specified from any thread to schedule a slot execution from the current affinity thread, which will change affinity from the right thread to whatever thread you pass as a parameter.
But seeing how you try to change it from inside the class, that should work as expected, as long as saveToAll() is invoked via the signal/slot mechanism (rather than directly from just about any thread).
//Error QCoreApplication has no member thread()
It most certainly does according to the documentation.

QT - force an object to process incoming signals

I am wondering how to tell a QObject to process all signals and call the slots associated with them. Here's the concrete problem I am having, for a better description of the question:
My program consists of three Qthreads : Main, Communication and Input.
The communication thread handles communication via the network, the Input thread handles user input, and both have several signal-slot connections to the main thread. Whenever a network event occurs, or whenever the user inputs a commandline command, a signal from the respective thread is called, which then activates the appropriate connected slot in the main thread. The main thread's role is to process these events. My code looks as follows:
QApplication a(argc, argv);
CommObj co; //inherits from QThread
co.start(); //Starts the thread
InputObj io; //inherits from QThread
io.start(); //Starts the thread
MainObj u(&co,&io);
return a.exec();
Now, what I want to achieve is for the main thread to not reach the last line.
My intentions are to call a method run() within the constructor of MainObj which is going to do something along the lines of this:
void run ()
{
forever
{
//process all signals..
}
}
However, I do not know how to implement the process all signals part. Any advice on how this could be done (including workarounds) would be very welcome.
This is completely unnecessary. a.exec() runs an event loop that will receive and process the events sent by other threads.
When a slot is invoked due to a signal being emitted in a different thread, Qt is posting a QMetaCallEvent to the receiver object. The QObject::event method is able to re-synthesize the slot call based on the data in the event.
Thus, you need to do nothing. a.exec() does what you want. Feel free to invoke it from MainObj's constructor, as qApp->exec() or as QEventLoop loop; loop.exec(), but that's rather bad design.
The real questions are:
Why do you need MainObj's constructor to spin an event loop?
What sort of "user input" are you processing in the io? You can't access any GUI objects from that thread.
Why are you deriving from QThread if you're using Qt's networking? You definitely don't want to do that - it won't work unless you spin an event loop, so you might as well just use a QThread without changes. Well, to be safe, you need just to make the thread destructible, so:
class Thread {
using QThread::run; // make it final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { requestInterruption(); quit(); wait(); }
};
Anyway, by not using standard QThread that spins an event loop, the communication will be one way. Nothing in such threads will be able to react to signals from other threads.
You need to rearchitect as follows:
Use the Thread class as above. It's safe to be destructed at any time.
Have worker objects that run asynchronously using signals/slots/timers.
Move constructed workers to their threads.
What you need is the processEvents function. For example, if you don't want the user to be able to interact with widgets, but you want the graphics to update, use
processEvents(QEventLoop::ExcludeUserInputEvents);
See the documentation for details.

How to setup signal/slot connection between thread and child thread?

I have a class ParentThread deriving from QThread with the following run() method that roughly looks as follows:
void ParentThread::run()
{
QThread *childThread = new QThread;
QObject::connect(childThread, SIGNAL(finished()), this, SLOT(onChildThreadFinished());
QObject::connect(childThread, SIGNAL(finished()), childThread, SLOT(deleteLater());
childThread->start();
exec();
}
The slot onChildThreadFinished() is defined on ParentThread, and should run in the context of ParentThread. However, using the code above, onChildThreadFinished only gets called in case the signal/slot connection is a Qt::DirectConnection, but then runs in the context of the child thread. In case the signal/slot connection is defined as a Qt::QueuedConnection, the slot never gets called. I am using Qt 4.8.5. Any idea what the issue is here?
You state that The slot onChildThreadFinished() is defined on ParentThread, and should run in the context of ParentThread. This assumption is wrong. This is one of the reasons why subclassing QThread is discouraged.
If you want to use slots in your threads, subclassing QThread is not what you want to do. Use worker-object method instead. Subclass QObject and call QObject::moveToThread to move your object to a new thread.
Here is what Qt docs say about this:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

Qt Thread object only sending signal as Qt:DirectConnection - why?

I have a class derived from QThread: class MyClass : public QThread
This class is connected with a slot of another object. Originally this was connected as Qt::AutoConnection. But then - as soon as the thread is started (MyClass::run()) - the signal is no longer "reaching the slot" (why?).
// connected before myObject->run()
s = QObject::connect(
_myObject, SIGNAL(signalLogMessage(const QString&, QtMsgType)),
this, SLOT(slotLogMessage(const QString&, QtMsgType)), Qt::DirectConnection);
My first idea was that I need to force Qt::QueuedConnection (this / _myObject will be cross threaded). In this case it does not work at all. Only Qt::DirectConnection works. After the thread is started, IMHO Qt::QueuedConnection is the correct choice (cross thread).
Any idea what is going wrong? The connection itself seems to be correct, otherwise it was not working at (mean even not with Qt::DirectConnection).
Edit 1: -- As of hyde's answer / Nikos' comment
As of right now I think hyde's answer / Nikos' comment are pointing out the root cause. My QThread is running it's own message loop for another application. This is the reason why it is running in its own thread and is basically an infinite loop
run() {
// exec(); // while not reached
while (_runMessageLoop && ...) {
hr = CallDispatch(.....);
if (hr== 0) QThread::msleep(100);
// QCoreApplication::processEvents();
}
}
Guess due to this infinite loop the Qt message loop is not running and no signal / slots are processed (is this correct?) When forcing Qt::DirectConnection the methods are called directly with no Qt message loop required, this might be the reason why this is the only connection type working.
The question is now, how can I combine the Qt and my own message loop (if this is feasible)? Cannot call exec() before the loop (because then it is in the Qt loop), and just the QCoreApplication::processEvents(); in "my loop" is still not working.
=> see new Question here: How to combine own message loop and Qt event loop?
Hard to say without seeing all the code, but it may be because of this:
QThread object itself is not the thread, it's the thread controller. Most importantly, QThread object's thread affinity should not be the thread it controls. If your thread runs Qt event loop, then it's best to avoid subclassing QThread. Instead, have your logic (inter-thread slots etc) in another QObject, which you move to the thread you created with moveToThread after creating it. Only real reason to subclass QThread is to override run() method with one which does not call exec().
Related reading:
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
Addition:
If you override QThread::run(), you have to call QThread::exec() there or event loop won't be running and no non-direct signal gets delivered to any QObject with that thread affinity. If you want to have your own event loop, that is possible, you just have to call QCoreApplication::processEvents() to process Qt events.