Why no SIGNAL from QtFutureWatcher ...?
-
I am posting this to ask a simple question , and I do not feel it should be buried at the end of another discussion which was about HOW to actually code "connect".
This post is NOT about coding "connect" , I just want to know WHY I cannot get expected SIGNAL from QtFutureWatcher / QtFutuure / QtConncurent.
I can manually emit "started".
I can verify
isStarted - obviously it will pass testthen I remove the "emit ' and get
START run setFuture @ line "2471" watcher_new.isStarted() true watcher_new.isRunning() true watcher_new.isFinished() false END run setFuture @ line "2488"
so it STARTed , it is RUNNING, it is NOT finished
but
I did not get expected SLOT function to run on "started" !
( I know the connect is OK , it run fine after posting "emit ')
It "isRunning" ....so if it started and is running why no SIGNAL (on started) ?
that is my question
I can verify both states - but QtFutureWatcher does not emit expected 'started" SIGNAL.
and it does finish !
why am I not getting the SIGNAL(s) ?
watcher_new.setFuture(QtConcurrent::run( std::bind( hci_inquiry, dev_id, len, max_rsp, lap, //NULL, &ii, flags) )); emit watcher_new.started(); qDebug()<<" watcher_new.isStarted()" << watcher_new.isStarted(); qDebug()<<" watcher_new.isRunning()" << watcher_new.isRunning(); qDebug()<<" watcher_new.isFinished()" << watcher_new.isFinished(); qDebug()<<" watcher_new.isStarted()" << watcher_new.isStarted(); qDebug() <<" END run setFuture " << " @ line " << QString::number(__LINE__); //watcher_new->waitForFinished();
-
@AnneRanch said in Why no SIGNAL from QtFutureWatcher ...?:
qDebug()<<" watcher_new.isFinished()" << watcher_new.isFinished();
All I can see is that the concurrent code is not done running by the time you hit this debug statement.
If you do this does it change the output:emit watcher_new.started(); watcher_new->waitForFinished(); qDebug()<<" watcher_new.isStarted()" << watcher_new.isStarted(); qDebug()<<" watcher_new.isRunning()" << watcher_new.isRunning(); qDebug()<<" watcher_new.isFinished()" << watcher_new.isFinished(); qDebug()<<" watcher_new.isStarted()" << watcher_new.isStarted(); qDebug() <<" END run setFuture " << " @ line " << QString::number(__LINE__);
You can also tie a function to the signal of the QFutureWatcher::finished to tell you when it completes running the concurrent code.
-
This post is NOT about coding "connect" , I just want to know WHY I cannot get expected SIGNAL from QtFutureWatcher / QtFutuure / QtConncurent.
It is exactly about that. If do not connect the sender to the receiver correctly (or at all) and manage the lifetimes of these objects then you will never receive signals. You are not receiving a signal because something in your code is incorrect or because object lifetimes are not being managed.
Here is a single-file example that demonstrates clearly that such signals are sent and received. Feel free to compare it to your code to see where you are going wrong.
#include <QCoreApplication> #include <QObject> #include <QTimer> #include <QtConcurrent> #include <QDebug> int longRunningWhatnot() { qDebug() << "Enter" << Q_FUNC_INFO; // Three second delay QEventLoop wait; QTimer::singleShot(3000, &wait, &QEventLoop::quit); wait.exec(); qDebug() << "Leave" << Q_FUNC_INFO; return 42; } class Test: public QObject { Q_OBJECT public: explicit Test(QObject *p = nullptr): QObject(p) { qDebug() << "Enter" << Q_FUNC_INFO; watcher = new QFutureWatcher<int>(this); connect(watcher, &QFutureWatcher<int>::started, this, &Test::started); connect(watcher, &QFutureWatcher<int>::finished, this, &Test::finished); watcher->setFuture(QtConcurrent::run(&longRunningWhatnot)); qDebug() << "Leave" << Q_FUNC_INFO; } ~Test() { } private: void started() { qDebug() << "Call" << Q_FUNC_INFO; } void finished() { qDebug() << "Call" << Q_FUNC_INFO; qDebug() << "Returned" << watcher->result(); } QFutureWatcher<int> *watcher; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Test test; // ensure program terminates after 10 seconds QTimer::singleShot(10000, &a, &QCoreApplication::quit); return a.exec(); } #include "main.moc"
Output is:
Enter Test::Test(QObject*) Leave Test::Test(QObject*) Call void Test::started() Enter int longRunningWhatnot() Leave int longRunningWhatnot() Call void Test::finished() Returned 42
BTW: SHOUTING every third word will NOT lead to better responses. Writing straightforward, informative questions will get you a lot further.
-
I think I realized the cause of my problem.
Allow me to make another pass on theory.
QT is an event driven "system /banana"
The main "object / loop" is wrapper for everything " under it "skipping to my next object / loop is my
MDI - which is another wrapper for my "menu items"
then comes my "Bluetooth " object / loop/class .
one of the sub object / loop / classes "push button" task is to
run (function ), using QtConncurent ) external ( library ) function
QtConcurrent :run builds additional threads
AND EXITS
THEN "PUSH-BUTTON" EXITS**THEN THIS EXTERNAL function EXITS (posting "finished" SIGNAL ** after about 10 seconds
after the external function is finished , and "finished" SIGNAL is emitted ( it really does not matter by whom at this point of discussion )
and if they are emitted WHO can receive them ?
- The function who defined the "connect" no longer runs
- If so - are the newly created threads also terminated"?
- Did the newly created threads started in what loop / object ?
I would appreciate real comments on my theory, I am not fond of the terminology I use and really do not need my terminology challenged.
Cheers
Just the fact ma'am...
-
@AnneRanch said in Why no SIGNAL from QtFutureWatcher ...?:
and if they are emitted WHO can receive them ?
An object that needs the info. Maybe the parent of push button or the push button itself. You could also run a lambda that creates a dialog to tell the user the function is complete. Or maybe a widget the parent of push button knows about that shows that a process is running in the background.
Your understanding of the process is sufficient.
The thread, when the code inside completes, will clean itself up. You should probably lock out the button from being pressed again until it completes. This would require the button to have a function that updates its state when the thread completes. This would be a candidate for something that receives this signal. Also, you have have multiple objects connected to the signal if they need to do different things.
-
@fcarney I have done that in past - it behaves as expected.
Here is my latest "guess how it works "
after button press is detected i run a function - in normal sequence - from top to end...
I setup hci function values , then i setup for QTConcurrent to "run" the hci function. That includes "connect" to be able to process the hci function results - specifically after QTconcurrent "finishes".
The purpose / reason for using QTConcurrent - I want the main thread to complete the function started by push button. This is part of application tasks and I do not want to wait for hci to complete and block the main thread. ...Reason for "waitForfinished " is strictly a debug code.
Now here is probable cause of all this contrary of what was discussed in the other thread .
The "QTConcurent " runs the hci function in another threads, however according to documentation - the "futurewatcher " changes according of current state. That has been verified. on "started" and "running".
But these are NOT SIGNAL and even is so the QtConcurent call DOES NOT sit there - it done its job starting the hci function and the "push button " function is long terminated. The hci function completes in about 10 seconds and that has been verified - by "wait for finished " debug code .
The process is out of the "button " function and it is time for SIGNAL - coming from the other threads - to be processed.
That is NOT happening.
... and the "connect" has been verified....all this contrary of what was discussed in the other thread .
If code for "connect" is in main thread -
does it work when SIGNAL is coming from another thread ?I do not know how to verify that.
i know QtConcurrent generate "finished" but my "connect" is not working...
At this point of development I am in control of "waiting for the external function" . Adding a code to show that would be superficial.
I got nothing against lambda but prefer the original KISS approach.I just moved all pertinent stuff to class/ object constructor and still not getting startup SIGNAL. But it looks better....
I;ll change the connect to lambda.... -
@AnneRanch said in Why no SIGNAL from QtFutureWatcher ...?:
If code for "connect" is in main thread -
does it work when SIGNAL is coming from another thread ?Yes, by default a connection can work across threads. There is a parameter in the connect call to change this behavior, but there is no reason to change from default. The time it won't work is when the objects forming the connection get deleted. So the QtFutureWatcher needs to remain somewhere it does not get destroyed. One strategy is to allocate a QtFutureWatcher with new:
QtFutureWatcher* watcher = new QtFutureWatcher; watcher->connect(watcher, QtFutureWatcher::finished, watcher, QtFutureWatcher::deleteLater); // this will manage the memory for you.
All connections will be serviced before the QtFutureWatcher is destroyed. My guess is your watcher gets destroyed when you leave the scope of the button callback. So it cannot signal anything. I think my syntax is correct, but you will have to check.
Also, the QtFutureWatcher does not exist in the other thread. Whatever it calls does. I don't see you connecting to anything inside the thread in this code. Just the QtFutureWatcher that just manages the future.
-
@fcarney Just came to same conclusion and have the SIGNAL/SLOT finally working.
In retrospect- Engaging in discussion about new and old "connect" did not solve the problem. The old "connect" give plenty of messages when there is a mismatch. End of story.
- Understanding the relations between layers of "loops/ object/classes "" was the key. Prior to that just following some advises proved to be wrong...
- Debugging multithreaded code is not much fun...and never was
- When outputting too many debug messages one can miss some important
ones - I missed connect messages when I originally (!) put them in constructor . After I put them back and actually red them, things improved much,
( 5. My presentation style is my business )
I appreciate all the help given by many on this forum.