threads and created objects
-
wrote on 6 Oct 2020, 17:22 last edited by
Hi all -
I'm trying to clean up a lingering issue with an app. The app creates a second thread, into which I move my worker object:
int main(int argc, char *argv[]) { int rc; QApplication a(argc, argv); ModelDevice modelDevices(nullptr); ModelApScan modelApScan(nullptr); QThread thread(&a); Widget widget(&modelDevices, &modelApScan); Worker worker(&modelDevices); widget.setWorker(&worker); worker.setWidget(&widget); worker.moveToThread(&thread); QObject::connect(&widget, &Widget::quitButtonPushed, &thread, &QThread::exit); QObject::connect(&thread, &QThread::finished, &a, &QApplication::quit); QObject::connect(&thread, &QThread::started, &worker, &Worker::start); widget.show(); thread.start(); rc = a.exec(); return rc; }
The worker object creates another object:
Worker::Worker(ModelDevice *modelDevices) : m_modelDevices(modelDevices) { m_mcastSocket = new UdpSocket(&m_addrMulticast, this); }
The destructor for UdpSocket is this:
UdpSocket::~UdpSocket() { m_timer.stop(); }
On the call to stop(), I get this message:
QObject::killTimer: Timers cannot be stopped from another thread
It seems to me that UdpSocket, being created in Worker::start(), should belong to the Worker thread, no? What am I doing wrong here?
Thanks...
-
Hi,
If you want everything to happen in the worker thread, allocate your Worker object on the heap and connect deleteLater to the thread finished signal.
-
@mzimmers said in threads and created objects:
worker.setWidget(&widget);
Why? You must not access gui from another thread than the main thread.
-
@mzimmers said in threads and created objects:
worker.setWidget(&widget);
Why? You must not access gui from another thread than the main thread.
wrote on 6 Oct 2020, 17:58 last edited by mzimmers 10 Jun 2020, 18:08@Christian-Ehrlicher I do that so I can do things like this:
void Worker::start() { QObject::connect(m_widget, &Widget::discoverButtonPushed, this, &Worker::sendDiscoveryRequest); QObject::connect(m_widget, &Widget::scanButtonPushed, this, &Worker::sendScanRequest); ...
-
No need to do this inside start()
-
No need to do this inside start()
wrote on 6 Oct 2020, 18:02 last edited by@Christian-Ehrlicher well, it has to be done somewhere; are you suggesting it would be preferable to make the connections from the widget object?
-
Hi,
If you want everything to happen in the worker thread, allocate your Worker object on the heap and connect deleteLater to the thread finished signal.
-
@mzimmers said in threads and created objects:
why doesn't an object created in worker::start() belong to worker?
It's important to which thread the objects belong to. Please show the UdpSocket ctor - there I see the only reason why the UdpSocket should not be moved to the thread where you move Worker to.
-
Object belonging and thread affinity are different things.
The message you had was because the destruction happened in the main thread.
-
@mzimmers said in threads and created objects:
why doesn't an object created in worker::start() belong to worker?
It's important to which thread the objects belong to. Please show the UdpSocket ctor - there I see the only reason why the UdpSocket should not be moved to the thread where you move Worker to.
wrote on 6 Oct 2020, 18:10 last edited byUdpSocket::UdpSocket(QHostAddress *qha, QObject *parent) : QObject(parent) { QHostAddress *l_qha; QString qs; // set up addresses. l_qha = qha; qs = l_qha->toString(); m_addrMulticast.setAddress(qs); init(); QObject::connect(&m_timer, &QTimer::timeout, this, &UdpSocket::checkSockets); m_timer.start(3000); }
-
Object belonging and thread affinity are different things.
The message you had was because the destruction happened in the main thread.
wrote on 6 Oct 2020, 18:12 last edited by@SGaist said in threads and created objects:
Object belonging and thread affinity are different things.
I didn't realize that, but OK.
The message you had was because the destruction happened in the main thread.
So, how is this changed by creating worker on the heap?
-
Object belonging and thread affinity are different things.
The message you had was because the destruction happened in the main thread.
@SGaist said in threads and created objects:
The message you had was because the destruction happened in the main thread.
Correct, I read it the other way and thought the timer was still in the main thread and was destructed in the other thread :)
-
Your object on the stack gets destroyed at the end of the current scope.
Moving it on the heap gets it out of that scope, but then it's your duty to delete it properly. Which you do by connecting the deleteLater slot to the finished signal.
-
Object belonging and thread affinity are different things.
The message you had was because the destruction happened in the main thread.
wrote on 7 Oct 2020, 18:53 last edited by@SGaist said in threads and created objects:
Object belonging and thread affinity are different things.
I need to pursue this a bit further. So, if I have an object (my worker object) that I move to another thread, is it true that anything created within that object prior to the move "belongs" to the original thread?
Specifically, my worker object has a member object m_serial. Presumably this object belongs to the original thread. After worker is moved, when this object creates something (like a QSerialPort), this "belongs" to the worker thread. When the worker thread does a write on it, I get the timer error. Is this because m_serial belongs to the original thread, but its QSerialPort belongs to the worker thread?
And if I have this right, is the solution that the worker thread would create its objects in start(), instead of having member objects?
-
Lifetime Qt Championwrote on 7 Oct 2020, 19:02 last edited by SGaist 10 Jul 2020, 19:26
@mzimmers said in threads and created objects:
I need to pursue this a bit further. So, if I have an object (my worker object) that I move to another thread, is it true that anything created within that object prior to the move "belongs" to the original thread?
If it's a QObject that is properly parented, it will move with it. Note that classes like QTcpSocket must be created in the new thread. You can however pass the descriptor like shown in the threaded QTcpSocket/Server example.
-
@mzimmers said in threads and created objects:
I need to pursue this a bit further. So, if I have an object (my worker object) that I move to another thread, is it true that anything created within that object prior to the move "belongs" to the original thread?
If it's a QObject that is properly parented, it will move with it. Note that classes like QTcpSocket must be created in the new thread. You can however pass the descriptor like shown in the threaded QTcpSocket/Server example.
@SGaist said in threads and created objects:
If it's a QObject that is properly patented, it will move with it. Note that classes like QTcoSocket must be created in the new thread. You can however pass the descriptor like shown in the threaded QTcpSocket/Server example.
Actually a comment on that. Sockets that haven't been opened/bound can still be moved normally, however I agree it's a bad practice to depend on the actual implementation.
-
@mzimmers said in threads and created objects:
I need to pursue this a bit further. So, if I have an object (my worker object) that I move to another thread, is it true that anything created within that object prior to the move "belongs" to the original thread?
If it's a QObject that is properly parented, it will move with it. Note that classes like QTcpSocket must be created in the new thread. You can however pass the descriptor like shown in the threaded QTcpSocket/Server example.
wrote on 7 Oct 2020, 19:15 last edited by@SGaist said in threads and created objects:
If it's a QObject that is properly patented, it will move with it.
This is my current creation:
class Worker : public QObject { Q_OBJECT private: SerialPort m_serial; ... SerialPort::SerialPort(QObject *parent) : QObject (parent) { ...
Note that classes like QTcoSocket must be created in the new thread.
But not in the c'tor, correct? Because that is called prior to the thread move, so it would pertain to the original thread?
-
I fixed the typo of parented (damn autocorrect...)
Yes, m_serial will not be moved.
-
wrote on 7 Oct 2020, 19:23 last edited by mzimmers 10 Jul 2020, 19:23
@SGaist said in threads and created objects:
I fixed the typo of parented (damn autocorrect...
Well, while you're at it..."QTcoSocket?"
-
@SGaist said in threads and created objects:
I fixed the typo of parented (damn autocorrect...
Well, while you're at it..."QTcoSocket?"
Moderatorswrote on 7 Oct 2020, 19:24 last edited by kshegunov 10 Jul 2020, 19:31If you want the
QObject
s to to be moved alongside with their parent to another thread, then you must pass them the parent. No parent, no way Qt to know whether the object's supposed to be moved.
1/26