QTHREADS requests
-
Excuse the blissful ignorance!!
A) Is it possible to launch an execution of a method by indicating a threads different from the method that requests it?
B) Is it possible to launch a series of different threads within a cycle, therefore with dynamic settings? I tried it and I got it on the first launch
QThread: Destroyed while thread is still running
C) Is it necessary to create a specific class to manage them?
D) Is it possible to run a Threads for a signal? I noticed that if I have a signal in a loop, they are carried out in the indicated sequence but all at the end of the method that calls them.*
All the examples found refer to threads launched in parallel but constantly defined in a class. Is there an exhaustive link to understand how they work in QT and how to apply them?
Does anyone have a simple and practical example of multiple threads running in parallel? -
@elicat
A) Yes, for example using https://doc.qt.io/qt-6/qtconcurrentrun.html
B) Yes, the error you got indicates that you destroyed the QThread instance before stopping it, fix that
C) No
D) No, but signals/slots work across threads. The problem you describe is simply that your loop blocks the Qt event loop, has nothing to do with threads. As long as the event loop is blocked no signals will be handled.There are many examples: https://doc.qt.io/qt-6/qthread.html, "See also"
-
@jsulm Thanks for the general information. ..
A) I had already tried to use it but I probably have to delve deeper, did I understand correctly that the variables that are declared in the calling method cannot be manipulated even if passed as pointer memory?About the point B, right away code example .
You rightly point me to the solution by saying "you destroyed the QThread instance before stopping it: fix it" but I don't destroy the QThread instance, at least not intentionally so I don't know how to fix itfor (int i = 0; i < arrayDataRowLauncher.size(); i++) { . . . . EngineIndexHtml* workerEngineIndexHtml; QThread workerThreadEngineIndexHtml; workerThreadEngineIndexHtml.moveToThread(&workerThreadEngineIndexHtml); connect(workerEngineIndexHtml, &EngineIndexHtml::elabSignal, this, &EngineIndexHtml::elabSignal); // Starting the worker thread workerThreadEngineIndexHtml.start(); emit elabSignal(jsonObjectDataRowLauncher); . . . }
About the point D, chi può o chi determina il blocco degli eventi in un caso semplice ocme nel codice di esempio ?
for (int i = 0; i < arrayDataRowLauncher.size(); i++) { . . . . if (fileFinish.exists()) { rowStyle["background-color"] = "#98fb98"; rowStyle["color"] = "#FFFFFF"; jsonObjectDataRowLauncher["pq_rowstyle"] = rowStyle; } else { rowStyle["background-color"] = "yellow"; rowStyle["color"] = "black"; jsonObjectDataRowLauncher["pq_rowstyle"] = rowStyle; } emit elabSignal(jsonObjectDataRowLauncher); . . . . }
-
@elicat said in QTHREADS requests:
variables that are declared in the calling method cannot be manipulated even if passed as pointer memory?
Not sure what you mean here. Are you talking about parameters for the function you're running in another thread? Please explain better what you mean.
"but I don't destroy the QThread instance" - you clearly do, think about the lifetime of workerThreadEngineIndexHtml.
"chi può o chi determina il blocco degli eventi in un caso semplice ocme nel codice di esempio ?" - I don't understand this.
-
@jsulm
point A) into method elabSignal if I put this type of variables.... emit elabSignal(¶m1, ¶m1); .. now i read param1 changed from elabSignal
point B) Are you telling me that when the loop goes into the second item the threads are still going but I destroy it by trying to iterate another one and that I should wait first? There is a reason but in this way I wouldn't launch N threads in parallel that all do the same thing passing different parameters, but I would launch an execution of a method in a different thread and I would have to wait for its end before I can execute another one... But not this is what I would like to achieve...
I would like to launch different treads that run and extinguish independently. I hope I made myself understoodpoint D) You tell me : "As long as the event loop is blocked no signals will be handled" and I asked " Who block IT into loop example ?
for (int i = 0; i < arrayDataRowLauncher.size(); i++) { . . . . if (fileFinish.exists()) { rowStyle["background-color"] = "#98fb98"; rowStyle["color"] = "#FFFFFF"; jsonObjectDataRowLauncher["pq_rowstyle"] = rowStyle; } else { rowStyle["background-color"] = "yellow"; rowStyle["color"] = "black"; jsonObjectDataRowLauncher["pq_rowstyle"] = rowStyle; } emit elabSignal(jsonObjectDataRowLauncher); . . . . }
-
@elicat said in QTHREADS requests:
emit elabSignal(¶m1, ¶m1);
If you pass pointers to some data to this signal, then of course the slot can modify the data these pointers point to, basic C++.
"Are you telling me that when the loop goes into the second item the threads are still going but I destroy it by trying to iterate another one and that I should wait first?" - yes, again basic C++:
for (int i = 0; i < arrayDataRowLauncher.size(); i++) { . . . . EngineIndexHtml* workerEngineIndexHtml; // On each iteration of this loop previous workerThreadEngineIndexHtml is destroyed and new one is created QThread workerThreadEngineIndexHtml; }
Don't wait, simply make sure all this QThread instances live long enough (you can make them class members or allocate on the heap).
"Who block IT into loop example ?" - your loop is blocking the event loop. It is simple: as long as your code is running event loop is not executed. Only if your code finishes the event loop is executed again and can process the signals. This is how event driven applications work in general.
-
@jsulm said in QTHREADS requests:
event loop is executed again and can process the signals
Better: can execute the slots connected to the signals. The receiver event loop is blocked.
-
@elicat said in QTHREADS requests:
Are you telling me that when the loop goes into the second item the threads are still going but I destroy it by trying to iterate another one and that I should wait first? There is a reason but in this way I wouldn't launch N threads in parallel that all do the same thing passing different parameters, but I would launch an execution of a method in a different thread and I would have to wait for its end before I can execute another one... But not this is what I would like to achieve...
I would like to launch different treads that run and extinguish independently. I hope I made myself understoodSince you create the
QThread
on stack and inside the for loop, it will go out of scope, as @jsulm said and therefore is destroyed afterwards.
When you want to manage multiple threads, better useQThreadPool
or create aQList<QThread*>
/QVector<QThread*>
and push pointers to your thread objects in there, so you keep access to them.Like this:
// main/mainwindow.cpp QList<QThread* > threadList; for (int i = 0; i < arrayDataRowLauncher.size(); i++) { // . . . QThread *thread = new QThread(); EngineIndexHtml* workerEngineIndexHtml = new EngineIndexHtml; workerEngineIndexHtml->moveToThread(thread); // connect signals // ... // signals for cleanup // if the worker only has one job, you want to add a signal to your worker that is emitted once the work is done // e.g. EngineIndexHtml::finished connect( workerEngineIndexHtml, &EngineIndexHtml::finished, thread, &QThread::quit); connect( workerEngineIndexHtml, &EngineIndexHtml::finished, workerEngineIndexHtml, &EngineIndexHtml::deleteLater); connect( thread, &QThread::finished, thread, &QThread::deleteLater); // make sure to take thread from list when doing this, so you dont have deleted pointers in your list // ... // add Thread to list threadList.append(thread); thread->start(); }
-
@elicat said in QTHREADS requests:
D) Is it possible to run a Threads for a signal?
Maybe an additional note for this question: It is not possible to run a thread for a signal, but in some sense it is possible to run a thread for a slot. In the code of @Pl45m4 you already see the use of
moveToThread()
. If you create a worker object (derived from QObject, directly or indirectly) you can move it to a thread and all slots are executed inside that thread if they have been called through a signal from whatever thread. Manually (without an extra worker object) this can be done by using QMetaObject::invokeMethod(...) with QAbstractEventDispatcher::instance(thread) as the first argument (I have a loop in front of this call waiting for the thread to actually have started:while(!QAbstractEventDispatcher::instance(thread)) QThread::currentThread()->msleep(1);
).
About point B: To say it with different words concerning lifetime of the thread:
QThread workerThreadEngineIndexHtml;
creates the thread on the stack. Stack variables are destroyed (just plain C++) at the end of the scope; which in your case is at the end of the loop. In Qt, whenever the QThread object is destroyed the underlying running thread is also destroyed. So, at the end of your loop the thread is destroyed. -
Hello, after reading your comments and performed multiple tests I solved it using the class QtConcurrent
I called a slot from html/js which contains the start of the process where the loop is executed
Solt Call method with process lancheur QtConcurrent
void EngineIndexHtml::execLauncherBackupJob(QJsonObject jsonParameter) { extern void execLauncherJob(EngineIndexHtml * EngineHtmlObj, QJsonObject jsonParameter); QtConcurrent::run(execLauncherJob, this, jsonParameter); }
Part of method execLauncherJob where EngineHtmlObj is mother class where there is declare signal
for (int i = 0; i < arrayDataRowLauncher.size(); i++) { . . . . emit EngineHtmlObj->elabCheckStatusLauncher(jsonObjectDataRowLauncher); goLauncher(jsonObjectDataRowLauncher, strOriginFolder, startThread, endThread, iCoreIndex); . . . . }
Now is all ok.
Thanks to everyone who supported me and put up with me -