inherite from QThread, but donnot overrider virtual void run(), is this OK?
-
inherite from QThread, but donnot overrider virtual void run(), is this OK?
class MyThread : public QThread { public: MyThread(QObject* parent) : QThread(parent) {} ~MyThread() { exit(); } protected: //virtual void run();//use the dafault QThread::run(). protected slots: void slot_SendEmail(const MyInfo& info) {......;} } void main() { MyThread t; connect(...,...,...,slot_SendEmail); t.start(); //and then emit the signal_SendEmail(const MyInfo& /*info*/) @MainThread in some class::function frequently }
@opengpu I don't think this is OK. There is a common mistake with QThread usage.
QThread is a Qt object which will control a thread, but QThread instance leaves in the thread in which the instance has been created, not in the created thread.
So the slots/signals of the MyThread class will be launched in the thread used to create the MyThread instance.A good practice for multi-threading with Qt, is to create a worker class and to move the instance to the thread, not to sub-class QThread.
Take a look at following links for more details:
- http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
- http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-2/
- https://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
- https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
-
@opengpu I don't think this is OK. There is a common mistake with QThread usage.
QThread is a Qt object which will control a thread, but QThread instance leaves in the thread in which the instance has been created, not in the created thread.
So the slots/signals of the MyThread class will be launched in the thread used to create the MyThread instance.A good practice for multi-threading with Qt, is to create a worker class and to move the instance to the thread, not to sub-class QThread.
Take a look at following links for more details:
- http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
- http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-2/
- https://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
- https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
@KroMignon thank you , i think you are right. the signal and slot will be both at MainThread...before this i normally overide the virutal run(), and mainly do things @run().
at this time, i just need to SendMail(const MyInfo& info), so i tried to make it simple, without loop @run() with a list. -
@opengpu I don't think this is OK. There is a common mistake with QThread usage.
QThread is a Qt object which will control a thread, but QThread instance leaves in the thread in which the instance has been created, not in the created thread.
So the slots/signals of the MyThread class will be launched in the thread used to create the MyThread instance.A good practice for multi-threading with Qt, is to create a worker class and to move the instance to the thread, not to sub-class QThread.
Take a look at following links for more details:
- http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
- http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-2/
- https://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
- https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
@KroMignon said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
So the slots/signals of the MyThread class will be launched in the thread used to create the MyThread instance.
Yep, I've just tested. @opengpu so you have to use worker object or implement
run()
. Both approaches are described in great detail in QThread documentation. -
class Worker : public QObject { Q_OBJECT public slots: void doWork(const QString ¶meter) { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); } signals: void resultReady(const QString &result); }; class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller() { Worker *worker = new Worker; worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(this, &Controller::operate, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResults); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } public slots: void handleResults(const QString &); signals: void operate(const QString &); };
thanks, and i will use this.
///////////////////////////////////////////////////////////////////////////////////////////////
is this OK?
the 'doWork' is slow, and the emit 'operate' is very very frequently.
so is it OK when the previous signal's 'doWork' is still not finished & the next (maybe more than one)'operate' is already emitted. -
class Worker : public QObject { Q_OBJECT public slots: void doWork(const QString ¶meter) { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); } signals: void resultReady(const QString &result); }; class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller() { Worker *worker = new Worker; worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(this, &Controller::operate, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResults); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } public slots: void handleResults(const QString &); signals: void operate(const QString &); };
thanks, and i will use this.
///////////////////////////////////////////////////////////////////////////////////////////////
is this OK?
the 'doWork' is slow, and the emit 'operate' is very very frequently.
so is it OK when the previous signal's 'doWork' is still not finished & the next (maybe more than one)'operate' is already emitted.@opengpu said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
so is it OK when the previous signal's 'doWork' is still not finished & the next (maybe more than one)'operate' is already emitted.
The worker QThread implements a QEventQueue, when a new signal emitted from Controller, it will be stored in message queue. And when slot has been processed on Worker, next message will be extract from queue. And so on.
More details can be found here: https://www.toptal.com/qt/qt-multithreading-c-plus-plus
Messages will be processed in the order of reception in WorkerThread.
I would to initialization of Thread and Worker like this:
Worker *worker = new Worker; // no need to hold pointer to worker QThread *workerThread = new QThread; // no need to hold pointer to worker thread connect(this, &Controller::operate, worker, Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResults); // delete worker on controller end connect(this, &QObject::destroyed, worker, Worker::deleteLater, Qt::DirectConnection); // stop and delete worker thread on worker end connect(worker, &QObject::destroyed, workerThread, [](QObject *){ quit(); wait(); deleteLater(); }, Qt::DirectConnection); worker->moveToThread(workerThread); workerThread.start();
-
@opengpu said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
so is it OK when the previous signal's 'doWork' is still not finished & the next (maybe more than one)'operate' is already emitted.
The worker QThread implements a QEventQueue, when a new signal emitted from Controller, it will be stored in message queue. And when slot has been processed on Worker, next message will be extract from queue. And so on.
More details can be found here: https://www.toptal.com/qt/qt-multithreading-c-plus-plus
Messages will be processed in the order of reception in WorkerThread.
I would to initialization of Thread and Worker like this:
Worker *worker = new Worker; // no need to hold pointer to worker QThread *workerThread = new QThread; // no need to hold pointer to worker thread connect(this, &Controller::operate, worker, Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResults); // delete worker on controller end connect(this, &QObject::destroyed, worker, Worker::deleteLater, Qt::DirectConnection); // stop and delete worker thread on worker end connect(worker, &QObject::destroyed, workerThread, [](QObject *){ quit(); wait(); deleteLater(); }, Qt::DirectConnection); worker->moveToThread(workerThread); workerThread.start();
@KroMignon said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
connect(this, &QObject::destroyed, worker, Worker::deleteLater, Qt::DirectConnection);
This is a race condition -
deleteLater
is a slot and it's not thread-safe. Don't force the connection type. -
i want to set a min time interval inside which the emit operate or the slot doWork should be INVALID and do nothing.
before when overrider the virtual run(), that's easy to do.how about this situation while using this worker-method?
eg. if doWork is implemented and until 1 min passed, the signal or slot should not emit or implemented in this 1 min. and the signal/slot doesnot be renmembered, just ignore them.
-
i want to set a min time interval inside which the emit operate or the slot doWork should be INVALID and do nothing.
before when overrider the virtual run(), that's easy to do.how about this situation while using this worker-method?
eg. if doWork is implemented and until 1 min passed, the signal or slot should not emit or implemented in this 1 min. and the signal/slot doesnot be renmembered, just ignore them.
Emit a deadline (
QDeadlineTimer
) along with the input data. In the slot check if the deadline has expired, and if so just return immediately. -
QElapsedTimer m_ElapsedTimer;
if ( !m_ElapsedTimer.isValid() || m_ElapsedTimer.hasExpired(timeout)) { emit signalSendEmail(); m_ElapsedTimer.restart(); }
i want to write like this, this will not restrict the 1st time emit, and since the 1st emit, the next emit is only allowed outof timeout milliseconds.
However, i want the exe runs very very long time. the qinit64 seems still not that long enough for the longest interval in theory(qint64 is only about 214783 seconds). What will happen if the real time interval is longer than this?
And what is the best method to get the longest time interval supportted in code? -
QElapsedTimer m_ElapsedTimer;
if ( !m_ElapsedTimer.isValid() || m_ElapsedTimer.hasExpired(timeout)) { emit signalSendEmail(); m_ElapsedTimer.restart(); }
i want to write like this, this will not restrict the 1st time emit, and since the 1st emit, the next emit is only allowed outof timeout milliseconds.
However, i want the exe runs very very long time. the qinit64 seems still not that long enough for the longest interval in theory(qint64 is only about 214783 seconds). What will happen if the real time interval is longer than this?
And what is the best method to get the longest time interval supportted in code?@opengpu See my answer in your other thread (https://forum.qt.io/topic/104026/about-the-longest-elapsed-time-in-qt). I really have no idea why you think it is 214783 seconds only when using qint64...
-
@opengpu See my answer in your other thread (https://forum.qt.io/topic/104026/about-the-longest-elapsed-time-in-qt). I really have no idea why you think it is 214783 seconds only when using qint64...
-
@opengpu said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
workerThread
workerThread donot need sleep?
@opengpu said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
workerThread donot need sleep?
No, they are not humans :-)
Why are you asking? A thread can sleep or be busy. -
@opengpu said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
workerThread donot need sleep?
No, they are not humans :-)
Why are you asking? A thread can sleep or be busy. -
@KroMignon said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
connect(this, &QObject::destroyed, worker, Worker::deleteLater, Qt::DirectConnection);
This is a race condition -
deleteLater
is a slot and it's not thread-safe. Don't force the connection type.@kshegunov said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
This is a race condition - deleteLater is a slot and it's not thread-safe. Don't force the connection type.
Where did you found this information.... I mean not thread safe?
Because on Qt Mailing list, Thiago Macieira (which is deep involved in Qt devlopement) has written:It's thread-safe with almost any operation, except one: the actual object's
deletion, of course.But we haven't documented it as such. It just happens to be due to the
implementation.==> cf. https://lists.qt-project.org/pipermail/interest/2015-October/019197.html
-
@jsulm ok, so it will automatically sleep when no signal or event, right?
because i used to overider the virtual run()
thanks@opengpu If you call exec() in your run() method then your thread will have an event loop and sleep if there is nothing to do. Else it will finish as soon as run() finishes (https://doc.qt.io/qt-5/qthread.html#run).
-
@opengpu If you call exec() in your run() method then your thread will have an event loop and sleep if there is nothing to do. Else it will finish as soon as run() finishes (https://doc.qt.io/qt-5/qthread.html#run).
-
@kshegunov said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
This is a race condition - deleteLater is a slot and it's not thread-safe. Don't force the connection type.
Where did you found this information.... I mean not thread safe?
Because on Qt Mailing list, Thiago Macieira (which is deep involved in Qt devlopement) has written:It's thread-safe with almost any operation, except one: the actual object's
deletion, of course.But we haven't documented it as such. It just happens to be due to the
implementation.==> cf. https://lists.qt-project.org/pipermail/interest/2015-October/019197.html
@KroMignon said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
Where did you found this information.... I mean not thread safe?
Documentation. There's no promise Qt made about it being thread safe, and as Thiago noted this is an implementation detail you're relying on. It may change in Qt6 (it may even change in Qt5) and then you're going to wonder why a nasty bug suddenly appeared in your codebase.
-
QElapsedTimer m_ElapsedTimer;
if ( !m_ElapsedTimer.isValid() || m_ElapsedTimer.hasExpired(timeout)) { emit signalSendEmail(); m_ElapsedTimer.restart(); }
i want to write like this, this will not restrict the 1st time emit, and since the 1st emit, the next emit is only allowed outof timeout milliseconds.
However, i want the exe runs very very long time. the qinit64 seems still not that long enough for the longest interval in theory(qint64 is only about 214783 seconds). What will happen if the real time interval is longer than this?
And what is the best method to get the longest time interval supportted in code?@opengpu said in inherite from QThread, but donnot overrider virtual void run(), is this OK?:
QElapsedTimer m_ElapsedTimer;
if ( !m_ElapsedTimer.isValid() || m_ElapsedTimer.hasExpired(timeout)) { emit signalSendEmail(); m_ElapsedTimer.restart(); }
i want to write like this, this will not restrict the 1st time emit, and since the 1st emit, the next emit is only allowed outof timeout milliseconds.
However, i want the exe runs very very long time. the qinit64 seems still not that long enough for the longest interval in theory(qint64 is only about 214783 seconds). What will happen if the real time interval is longer than this?
And what is the best method to get the longest time interval supportted in code?// first emit emit signalSendEmail(QDeadlineTimer(QDeadlineTimer::Forever)); // More emits // ... emit signalSendEmail(QDeadlineTimer::current() + 1000 * 3600); // 3600s = 1 hour
In the slot it's as easy to check as:
void Class::slotThatSendsEmails(const QDeadlineTimer & deadline) { if (deadline.hasExpired()) return; // Code that matters }