Unsolved Need more help with C++ code syntax - QTConncurent and template
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
- QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan,stringList) returns QVector <QStringList> and I have no idea how to write the code to access this return value
Actually,
QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan, stringList)
returnsQFuture<QVector<QStringList>>
in your case. Your code already passes this correctly to your QFutureWatcher.The important points are:
- QFuture stores the return value of your function.
- QFutureWatcher stores your QFuture.
So, you can retrieve the return value of HCI_Scan_Scan() by calling
auto returnValue = futureWatcher.future().result()
See
- I am thinking to implement "emit" to "switch back" to main process.
You don't need to implement or emit your own signal. Just connect a slot/function to QFutureWatcher's
finished()
signal. That should automatically run in the main thread after your 10 seconds have elapsed.QVector<QStringList> HCI_Scan_Dialog::HCI_Scan_Scan(QStringList *string_array)
Instead of passing a
QStringList*
as a function parameter, it is good practice to passconst QStringList&
instead. The same idea applies when passing a QVector or any other container. -
@JKSH said in Need more help with C++ code syntax - QTConncurent and template:
auto returnValue = futureWatcher.future().result()
Perhaps I missed something here , but I am getting this error
/media/d/QT/QT_PROJECT_CAT/CAT_V1/configuredialog.cpp:403: error: 'returnValue' does not name a type auto returnValue = futureWatcher.future().result(); ^
Is "auto " type "standard" in Qt or some option I forgot to set ?
I need to read all the links you have posted , but I noticed that " it will block until finished" . If that is the case my usage of QtConcurent is NOT what I expected , but I will know better after I get this "auto " resolved.
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
Is "auto " type "standard" in Qt or some option I forgot to set ?
This has nothing to do with Qt. "auto" is a C++ keyword and was introduced in C++11 if I remember correctly. What compiler do you use (compiler version is also important).
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
Is "auto " type "standard" in Qt or some option I forgot to set ?
auto
is a C++ keyword that asks the compiler to automatically deduce the datatype by looking at the surrounding code. In your case, the following two lines produce exactly the same outcome on a C++11-compliant compiler:auto returnValue = futureWatcher.future().result();
QVector<QStringList> returnValue = futureWatcher.future().result();
As @jsulm mentioned,
auto
has been part of the C++ standard for 10 years (but it was widely available on common compilers years before that).If your compiler is moderately old, you can enable C++11 by adding
CONFIG += c++11
to your .pro file and re-running qmake. Nonetheless, we highly recommend that you use a recent version of your compiler + IDE, and that you take advantage of C++11 features in your code (which includesauto
and powerful template features). -
@JKSH said in Need more help with C++ code syntax - QTConncurent and template:
QVector<QStringList> returnValue = futureWatcher.future().result();
Still no go.
/media/d/QT/QT_PROJECT_CAT/CAT_V1/configuredialog.cpp:402: error: 'class QFuture<void>' has no member named 'result' QVector<QStringList> returnValue = futureWatcher.future().result(); ^
More..
Adding
CONFIG += C++11creates havoc with QT examples where "nullptr" is used . Hence I have a choice to rebuild the entire application and undefine "nullptr".
No thanks at this point - to late in the game.PS
Thanks for the history lesson, however "auto" was introduced to C much . much earlier... -
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
class QFuture<void>' has no member named 'result'
You seem to use a
QFuture<void>
which has no result. In order to get any result from yourQFutureWatcher
'sQFuture
, you need to set a type.Like
QVector<T>
( ->QFuture<T>
)See here:
-
"Void" future, just the function is running with
QtConcurrent:run
, no return type.
(https://doc.qt.io/qt-5/qtconcurrentrun.html#passing-arguments-to-the-function) -
QFuture
is from typeQFuture<QString>
because the function, that runs inQtConcurrent:run
is returning aQString
(https://doc.qt.io/qt-5/qtconcurrentrun.html#returning-values-from-the-function)
So check your
QFutureWatcher
and yourQFuture
setup.Edit:
If this
QVector<QStringList> HCI_Scan_Dialog::HCI_Scan_Scan(QStringList *string_array)
is your function, your
QFuture
shouldn't be<void>
. Does your function actually return aQVector<QStringList>
/QStringList
? -
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
Thanks for the history lesson, however "auto" was introduced to C much . much earlier...
The
auto
keyword in C means a totally different thing from theauto
we are talking about here in C++, introduced at C++11. It may be confusing that they chose to use the same keyword for a different purpose, but there you are.The
auto
you are referring to in C is a storage/scope specifier. Theauto
we are talking about here in C++ is for type inference. Quite different. -
@Pl45m4 said in Need more help with C++ code syntax - QTConncurent and template:
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
class QFuture<void>' has no member named 'result'
You seem to use a
QFuture<void>
which has no result. In order to get any result from yourQFutureWatcher
'sQFuture
, you need to set a type.Like
QVector<T>
( ->QFuture<T>
)See here:
-
"Void" future, just the function is running with
QtConcurrent:run
, no return type.
(https://doc.qt.io/qt-5/qtconcurrentrun.html#passing-arguments-to-the-function) -
QFuture
is from typeQFuture<QString>
because the function, that runs inQtConcurrent:run
is returning aQString
(https://doc.qt.io/qt-5/qtconcurrentrun.html#returning-values-from-the-function)
So check your
QFutureWatcher
and yourQFuture
setup.Edit:
If this
QVector<QStringList> HCI_Scan_Dialog::HCI_Scan_Scan(QStringList *string_array)
is your function, your
QFuture
shouldn't be<void>
. Does your function actually return aQVector<QStringList>
/QStringList
?Seems that the discussion is back what I originally asked for help with
what is the correct syntax
to retrieve the data from "run " function " for further processing.
Yes, I did not clearly specify if each part is defined with correct types.BTW at this point it is immaterial if the "run:function" actually returns anything - I need to have correct syntax and return types first.
.
I'll recheck my definitions to make sure it is correct. -
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
error: 'class QFuture<void>' has no member named 'result'
QFutureWatcher<void>
does not expect a result (as implied by thevoid
), hence the error.Use
QFutureWatcher<QVector<QStringList>>
instead. (Also, double-check that HCI_Scan_Scan() indeed returns QVector<QStringList>)@Pl45m4 said in Need more help with C++ code syntax - QTConncurent and template:
If this
QVector<QStringList> HCI_Scan_Dialog::HCI_Scan_Scan(QStringList *string_array)
is your function, your
QFuture
shouldn't be<void>
. Does your function actually return aQVector<QStringList>
/QStringList
?A
QFutureWatcher<void>
can watch anyQFuture<T>
. However,QFutureWatcher<void>::future()
returnsQFuture<void>
, not the originalQFuture<T>
. -
@JKSH said in Need more help with C++ code syntax - QTConncurent and template:
However, QFutureWatcher<void>::future() returns QFuture<void>, not the original QFuture<T>.
Yes, that's what I wanted to say there :)
So
future().result()
on aQFuture<void>
shouldn't return herQStringList
orQStringList
-vector, but I cant see where the<void>
is coming from?! Must be aQFutureWatcher<void>
somewhere in the code, where we cant see it? -
@Pl45m4 said in Need more help with C++ code syntax - QTConncurent and template:
I cant see where the
<void>
is coming from?! Must be aQFutureWatcher<void>
somewhere in the code, where we cant see it?@AnneRanch's original post contains a variable named
futureWatcher
but it didn't show the type declaration. Judging from the error message, the declaration must have beenQFutureWatcher<void> futureWatcher;
That just needs to change to
QFutureWatcher<QVector<QStringList>> futureWatcher;
-
Found it :)
QFutureWatcher<void> is specialized to not contain any of the result fetching functions. Any QFuture<T> can be watched by a QFutureWatcher<void> as well. This is useful if only status or progress information is needed; not the actual result data.
See also QFuture and Qt Concurrent.
(https://doc.qt.io/qt-5/qfuturewatcher.html#details)
If you have a
<void>
type somewhere, you can't work with the result. -
FYI
After changing this// this is wrong // QFutureWatcher<void> futureWatcher; #ifdef BYPASS /media/d/QT/QT_PROJECT_CAT/CAT_V1/configuredialog.cpp:275: error: '>>' should be '> >' within a nested template argument list QFutureWatcher<QVector<QStringList>> futureWatcher; ^ #endif QFutureWatcher<QVector<QStringList> > futureWatcher;
The "run" function works as expected, however , the supporting QConcurrent " 1 seconds ticks" needs work.
qDebug()<< "test apply delay function spin to each vector setup map "; // test map vector array with spin function futureWatcher.setFuture(QtConcurrent::map(vector, spin));
/media/d/QT/QT_PROJECT_CAT/CAT_V1/configuredialog.cpp:465: error: no matching function for call to 'QFutureWatcher<QVector<QStringList> >::setFuture(QFuture<void>)' futureWatcher.setFuture(QtConcurrent::map(vector, spin)); ^
I'll try to fix that myself...
Appreciate all the help , it has been revealing how things can get complex if one does not pay attentions to ALL PARTS of the code.
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
The "run" function works as expected, however , the supporting QConcurrent " 1 seconds ticks" needs work.
Yes, because now you cant use your changed
futureWatcher
the same way as used by the Qt Example.
(spin
function doesn't return aQStringList
vector) -
@Pl45m4
Yes, I realized that. But I hacked it , at lest for now , by defining another
QFutureWatcherQFutureWatcher<QVector<QStringList> > futureWatcher_run; // 1 seconds tick // keep curent SIGNAL / SLOT QFutureWatcher<void> futureWatcher; // keep for SIGNAL etc 1 second ticks
Now as I suspected - I have lost the "concurrency" - the "run" , as coded , blocks process and I have no "concurrent" 1 second ticks running in QProgressDialog.
More fun work.... perhaps just checking for "result" AFTER the "concurrent " is done will work. QProgressDialog sits on top on the area which eventually will show the results , so no hurry until it is gone from view. -
I need to discuss / clarify ONE more "problem" .
I hope I can explain "the problem" using my interpretations of Qt documentation. It is somewhat dupe of what I have said / posted before.
My "primary objective" was to utilize / write multi threaded code to account for a function which takes abut 10 seconds to execute .
I am using "QtConcurrent "framework " which does support multi threading .
I do "QtConcurrent::run" to run time consuming function in ONE thread AND futureWatcher.setFuture(QtConcurrent::map(vector, spin)); in additional FOUR threads.
As is - It all works as expected.The "time consuming function" retrieves data for further processing.
I have a lengthy discussion elsewhere about how to pass / retrieve such data for such processing and it DOES work using following code:QVector<QStringList> returnValue = futureWatcher_run.future().result();
The problem is , as far as I can identify it - the futureWatcher_run.future().result() no longer "runs " as multi threaded / QtConcurrent framework - it appears to run in main thread and is blocking.
Am I wrong ?
I do not have code implemented to actually see / debug the thread execution of the above code.
I do realize my problem is harder to visualize without full code, but how can I verify / change the "returnValue" code to make sure it runs in QtConcurrent framework and in its OWN thread , and not to be blocking?
QStringList *stringList = new QStringList(); // temporary pass QStringList QElapsedTimer timerHCI; timerHCI.start(); futureWatcher_run.setFuture(QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan,stringList)); // test returnValue int returnValueIndex = 0; int returnValueSize = 0; qDebug()<< "futureWatcher.setFuture(QtConcurrent::run(HCI, " "&HCI_Scan_Dialog::HCI_Scan_Scan,stringList)) elapsed time " << timerHCI.elapsed() ; #ifdef BYPASS // takes real time QVector<QStringList> returnValue = futureWatcher_run.future().result();
-
@AnneRanch I' don't quite understand your situation, why do you think its not running in its own thread?
Any way, if you want to, take a look at my git repo
https://github.com/DeiVadder/QtThreadExampleIn that I have a project that covers all Qt ways of parallel processing, Related functions are number form 1 to 5.
Qt Concurrent is the number 4
-
@J-Hilk said in Need more help with C++ code syntax - QTConncurent and template:
@AnneRanch I' don't quite understand your situation, why do you think its not running in its own thread?
Actually - that is silly for me to say.
Of course it is running in its own thread, problem is it is NOT QtConcurrent - one of he expected multi threads .
But I cannot simply prove it - the "debug" is getting too complicated.
I know for sure it is blocking - it is causing the main window to "go gray".
That is from my initial experience - when I was not running QtConcurrent correctly - the main window would turn gray at completion of the function.I'll take a look at your code.
thanks.Any way, if you want to, take a look at my git repo
https://github.com/DeiVadder/QtThreadExampleIn that I have a project that covers all Qt ways of parallel processing, Related functions are number form 1 to 5.
Qt Concurrent is the number 4
-
@AnneRanch said in Need more help with C++ code syntax - QTConncurent and template:
Appreciate all the help , it has been revealing how things can get complex if one does not pay attentions to ALL PARTS of the code.
You're welcome. Indeed, complexity tends to grow exponentially.
futureWatcher.setFuture(QtConcurrent::map(vector, spin));
You started this thread by asking about
QtConcurrent::run()
, and now you're addingQtConcurrent::map()
to the mix. These two functions are very different.Let's step back a bit. First, please describe in your own words:
- What does
QtConcurrent::run()
do? What does it return? - What does
QtConcurrent::map()
do? What does it return?
perhaps just checking for "result" AFTER the "concurrent " is done will work.
Yes, you should do this.
The reason for the "block" is documented at https://doc.qt.io/qt-5/qfuture.html#result
- What does
-
@JKSH said in Need more help with C++ code syntax - QTConncurent and template:
- What does
QtConcurrent::run()
do? What does it return?
I "runs" time consuming function " which scans (HCI inquiry) for nearby bluetooth devices and returns their address and name.
- What does
QtConcurrent::map()
do? What does it return?
It "runs" QProgressDialog and updates its "progress bar" in roughly 1 second intervals . The interval is not important.
Thanks to QConcurrent these functions run in multiple threads , hence in 'parallel fashion " as far as the user is concerned.
perhaps just checking for "result" AFTER the "concurrent " is done will work.
Yes, you should do this.
The reason for the "block" is documented at https://doc.qt.io/qt-5/qfuture.html#result
I'll check that.
In the mean time - for entertainment purposes - here is somewhat sanitized version of basic code - the "result" code is still under construction.
{ # ifdef TRACE qDebug() << "QDEBUG TRACE START initialize time consuming task"; qDebug() << "file " << __FILE__; qDebug() << "function "<<__FUNCTION__; qDebug() << "@line " << __LINE__; //qDebug()<<"TEMPORARY EXIT "; // return;#ifdef BYPASS #endif qDebug() << " SETUP declare / define (?) consuming function QFutureWatcher<QVector<QStringList> > futureWatcher_run;"; QFutureWatcher<QVector<QStringList> > futureWatcher_run; qDebug() << " SETUP declare / define (?) QFutureWatcher<void> futureWatcher;1 second ticks"; QFutureWatcher<void> futureWatcher; // keep for SIGNAL etc 1 second ticks qDebug() << "SETUP # of iterations as vector array "; QVector<int> vector; //NOTE for now - # of iterations 3*4* estimated number of devices //TODO something smarter - use "finished" SIGNAL int iterations = 35; // temp MN for (int i = 0; i < iterations; ++i) { // first vector cSTART initialize time consuming taskontains time consuming function - no delay // rest of them - single delay time (1 S) #ifdef PROCESS //qDebug()<<" interations loop ?? index " << i; qDebug()<<" vector.append(i) index " << i; // LOOP "; // another delay "iterations //qDebug()<<" another delay iterations (?) "; #endif vector.append(i); } qDebug()<<"SETUP Create QProgressDialog dialog - set paramaters "; // this is a default QProgressDialog constructor QProgressDialog dialog; // QProgressDialog(const QString & labelText, // const QString & cancelButtonText, int minimum, int maximum, // QWidget * parent = 0, Qt::WindowFlags f = 0) #ifdef BYPASS QProgressDialog dialog ( "TEST window title ", " BUTTON text", 0, iterations ,0 ,0); //BUG did not set to TEST window title here // dialog.setWindowModality(Qt::WindowModal); #endif // dialog.labelText(" what is label ?" ); no matching function ?? dialog.setWindowTitle("TEST window title "); dialog.setFixedWidth(500); //W.setWindowTitle("TEST window title "); // set defaulrs of what ??? // dialog.setMaximum(100); // dialog.setRange(10, 1000 ); // If set to 0, the dialog is always shown as soon as any progress is set. // The default is 4000 milliseconds. // int minimumDuration() const // void setMinimumDuration(int ms) dialog.setMinimumDuration(0); // sets delay time to ~ 5 seconds dialog.setRange(0,0); // single shot label only //dialog.show(); //This is done querying the number of processor cores //NOTE won;t work unitil what is done ??? qDebug()<< "SETUP test timer"; QElapsedTimer timer; timer.start(); #ifdef BYPASS //TODO later dialog.setLabelText(QString("Progressing using %1 thread(s)...\nTODO Elapsed time %2 [mS] ") .arg(QThread::idealThreadCount()).arg(timer.elapsed())); dialog.show(); // test show #endif qDebug()<<"SETUP ALL connect function futureWatcher and dialog connect SIGNAL SLOT "; // # of iterations ?? " << iterations ; // vector.append(i) LOOP "; qDebug()<<"SETUP setup future WatcherSIGNAL(finished()"; // Resets the progress dialog. The progress dialog becomes hidden if autoClose() is true. //QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset())); // reset to what ?? qDebug()<<"SETUP setup dialog, SIGNAL(canceled()"; //QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel())); // TOK // how to emulate these ?? QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int,int)), &dialog, SLOT(setRange(int,int))); QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int))); // add tracking slot //QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), this , SLOT(setValue(int))); // create test SLOT to monitor progressValueChanged(int) qDebug() << "SETUP ! create test SLOT to monitor progressValueChanged(int)"; QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), this, SLOT(on_doTaskButton_2_clicked())); // QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)),this, SLOT(on_doTaskButton_3_clicked())); QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int,int)),this, SLOT(on_doTaskButton_3_clicked())); // create test SLOT to monitor progressValueChanged(int) qDebug() << "SETUP create test SLOT to monitor progressValueChanged(int)"; QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), this, SLOT(on_doTaskButton_2_clicked())); // &dialog.getValue()))); qDebug() << "SETUP HCI_Scan_Dialog *HCI = new HCI_Scan_Dialog () with HCI_Scan_Scan function "; HCI_Scan_Dialog *HCI = new HCI_Scan_Dialog (); // run HCI_Scan_scan with QStringList array as parameter qDebug() << "RUN futureWatcher_run.setFuture(QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan,stringList));"; QStringList *stringList = new QStringList(); // temporary pass empty QStringList QElapsedTimer timerHCI; timerHCI.start(); // takes no real time - but HCI_Scan_scan does ! futureWatcher_run.setFuture(QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan,stringList)); qDebug() << "CZECH futureWatcher_run.setFuture(QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan,stringList));"; qDebug() << "CZECH futureWatcher_run.setFuture(QtConcurrent::run(HCI, &HCI_Scan_Dialog::HCI_Scan_Scan,stringList)) elapsed time " << timerHCI.elapsed() << " mS" ; // NOTE no progress dialog here , no main window gray either // TODO get real thread ID here qDebug() << "RUN futureWatcher.setFuture(QtConcurrent::map(vector, spin));"; futureWatcher.setFuture(QtConcurrent::map(vector, spin)); The reason for the "block" is documented at https://doc.qt.io/qt-5/qfuture.html#result // test real duration of dialog here qDebug() << "RUN dialog.exec(); // run modal dialog;"; QElapsedTimer timer_wait; timer_wait.start(); // futureWatcher.progressValue() qDebug()<<"TODO ?? futureWatcher.progressValue() " << futureWatcher.progressValue(); // what is this for ?? dialog.exec(); // run modal dialog qDebug()<< "futureWatcher.setFuture(QtConcurrent::run(HCI, " "&HCI_Scan_Dialog::HCI_Scan_Scan,stringList)) elapsed time " << timer_wait.elapsed() ; }
PLEASE NOTE
The reason for the "block" is documented at https://doc.qt.io/qt-5/qfuture.html#result
Unfortunately to mitigate this "blocking / waiting for ANY ( first?) result " , which in my case takes 10 seconds - the "result" code , as suggested , cannot be simply placed willy-nilly .
It is back to "emit" SIGNAL or wait until "finished" SIGNAL is emitted.
I am already setup to emit "single device found" SIGNAL from the function itself, not from the "QConcurretn code ".It will take some care and time to add all the necessary emits , SIGNAL SLOT....
Thanks for all the forum help I am making some (slow) progress.
- What does