I'm doing tests with C ++ and Qt. I want to make a program that according to the data found in the database create X threads to make each of them a laaaargo process. This process must be repeated indefinitely while the user does not stop it.
For this you have two options: * Stop the process temporarily. Typical "start / stop". * Restart them.
Restarting them makes sense when the user has modified the data stored in the database or files (the configuration).
If I restart it I want to delete all . Eliminate dynamically created threads and objects that have been moved to these threads to perform the job. Then we would have to start the process from scratch.
I know you could tell the users to close the application and come back to execute it, but it would not be elegant. I would like to learn how to do it well.
This is the code I use for the tests:
myWorker.h
#ifndef MYWORKER_H
#define MYWORKER_H
#include <QCoreApplication>
#include <QObject>
#include <QDebug>
namespace jlu
{
class myWorker : public QObject
{
Q_OBJECT
public:
explicit myWorker ();
~myWorker ();
void setWorkerID (int workID);
signals:
void startProcess();
public slots:
void changeStatus (int id, bool newStatus);
void process();
private:
void loadConfigData();
// Propiedades de la clase:
bool isActive;
int myID;
};
}
#endif // MYWORKER_H
myWorker.cpp
#include "myworker.h"
jlu::myWorker::myWorker()
{
connect (this, SIGNAL (startProcess()),
this, SLOT (process()));
}
jlu::myWorker::~myWorker()
{
// Mensaje que uso para comprobar si se ha eliminado o no.
qDebug() << "Se ha eliminado al hilo con ID: " << myID;
}
void jlu::myWorker::setWorkerID (int workID)
{
if (0 <= workID)
{
myID = workID;
}
else
{
myID = 0;
}
}
void jlu::myWorker::changeStatus (int id, bool newStatus)
{
if (myID != id)
{
return;
}
isActive = newStatus;
if (isActive)
{
emit startProcess();
}
}
void jlu::myWorker::process()
{
loadConfigData(); // Carga toda la información necesaria para funcionar.
qDebug() << "Se inicia el proceso con id = " << myID;
while (isActive)
{
// Un laaargo proceso que se repita indefinidamente
// Atendemos los eventos que se hayan producido.
QCoreApplication::processEvents (QEventLoop::AllEvents);
}
qDebug() << "Proceso detenido.";
}
void jlu::myWorker::loadConfigData()
{
// Carga datos desde la base de datos.
// Carga datos de archivos de configuración etc.
}
manageWorkers.h
#ifndef MANAGEWORKERS_H
#define MANAGEWORKERS_H
#include <QObject>
#include <QThread>
#include <QDebug>
#include "myworker.h"
namespace jlu
{
class manageWorkers : public QObject
{
Q_OBJECT
public:
explicit manageWorkers (QObject * parent = nullptr);
~manageWorkers();
void loadAndStartAllWorkers();
signals:
void changeStatusOfWorker (int id, bool newStatus);
public slots:
void killallWorkers();
private:
int numWorkers;
QThread * myThreads = NULL;
myWorker * myProcess = NULL;
};
}
#endif // MANAGEWORKERS_H
manageWorkers.cpp
#include "manageworkers.h"
jlu::manageWorkers::manageWorkers (QObject * parent) : QObject (parent)
{
}
jlu::manageWorkers::~manageWorkers() {}
void jlu::manageWorkers::loadAndStartAllWorkers()
{
numWorkers = 4; // Esto es realmente el resultado de una consulta SQL
if (0 == numWorkers)
{
return;
}
myThreads = new QThread[numWorkers];
myProcess = new jlu::myWorker[numWorkers];
for (int i = 0; i < numWorkers; i++)
{
myProcess[i].setWorkerID (i); // Se tomará de la consulta realizada
myProcess[i].moveToThread (&myThreads[i]);
connect (&myThreads[i], SIGNAL (finished()),
&myProcess[i], SLOT (deleteLater()));
connect (this, SIGNAL (changeStatusOfWorker (int, bool)),
&myProcess[i], SLOT (changeStatus (int, bool)));
// Demás conexiones necesarias
myThreads[i].start();
// Iniciamos el proceso.
emit changeStatusOfWorker (i, true);
}
}
void jlu::manageWorkers::killallWorkers()
{
for (int i = 0; i < numWorkers; i++)
{
qDebug() << "Se detiene el hilo n. " << i;
emit changeStatusOfWorker (i, false);
myThreads[i].wait (1000);
myThreads[i].quit();
}
qDebug() << "Se han detenido todos los hilos";
}
main.cpp
#include <QCoreApplication>
#include <QTimer>
#include <QObject>
#include <QDebug>
#include <QThread>
#include <QDateTime>
#include "manageworkers.h"
#define DATETIME_FORMAT "yyyy-MM-dd HH:mm:ss"
// Programa principal solo para testear el reinicio de los objetos.
int main (int argc, char * argv[])
{
QCoreApplication a (argc, argv);
jlu::manageWorkers * myControl = new jlu::manageWorkers();
myControl->loadAndStartAllWorkers();
qDebug () << QDateTime::currentDateTime().toString (DATETIME_FORMAT);
QTimer::singleShot (10000, myControl, SLOT (killallWorkers()));
return a.exec();
}
In this code, what I do is manageWorkers create as many threads and "Workers" objects as necessary and initialize them. After 10 seconds of operation, only for tests and tests, I eliminate (at least that is what I am trying to do) the threads and associated "Workers" objects.
In theory when finishing a QThread the object "Worker" should be finished:
connect (&myThreads[i], SIGNAL (finished()), &myProcess[i], SLOT (deleteLater()));
But this does not work. The program breaks.
I have tried to change the order of the instructions:
myThreads[i].wait (1000);
myThreads[i].quit();
If I do alone:
emit changeStatusOfWorker (i, false);
myThreads[i].wait();
The process stops, but it is not deleted.
How can I solve this and delete correctly the "Workers" objects and the dynamically created threads?