Hi,
I'm renewing an old application by "threading" it. The idea is to deliver a (high) number of simulation tasks to the threads that the computer may have. After reading a lot about threading, I've used a QThreadPool in a "server" class to deliver the tasks. These tasks are implemented in a so-called "client" class. I also want to have information about the evolution of the thread operation, so the "server" class has a GUI where I show information about it, such as the status of the tasks (pending/in progress/completed), a progress bar, etc.
I've implemented the reporting from the threaded tasks through "invokeMethod", invoking in the "client" class two slots from the "server" class, in a similar way to the example in https://www.walletfox.com/course/qrunnableexample.php.
However, I'm getting some strange compiler errors:
* In the two invokeMethod calls ("no matching function for call to 'QMetaObject::invokeMethod(QWidget*&, ...").
* In "qobjectdefs.h" file ("no type named 'type' in struct std::enable_if<false, bool>'").
* In the moc file of the client's cpp file!!!
Probably all may be due to the same error (or errors), but I'm not able to catch. I want to remark that, although I comment the invokeMethod calls, the other errors persist...
In other posts I've seen that you suggested to delete the moc and ui files, the makefiles, etc. So, I've deleted completely the build folder, and recompiled the project as new. But the errors in the moc file do appear again.
Any idea? I enclose the h and cpp files for the "client" and "server" classes (although simplifying some irrelevant functions) in case they may help. If you consider necessary to upload all the application, please don't hesitate to ask, and I'll do.
Thanks!
Server.h
#ifndef SERVERMTH_H
#define SERVERMTH_H
#include <QFile>
#include <QFileInfo>
#include <QDialog>
#include <QMessageBox>
#include <QProcess>
#include <QProgressDialog>
#include <QString>
#include <QStringList>
#include <QThreadPool>
#include <QElapsedTimer>
#include "BasicDeclarations.h"
#include "ClientRunnable.h"
namespace Ui {
class ServerMTh;
}
{
Q_OBJECT
public:
int nbr_injections
= 0,
QStringList *macro_list
= nullptr,
~ServerMTh();
private slots:
void confirmAbort();
void ClientStarted(int id_client);
void ClientTerminated(int id_client, int client_status);
private:
enum
{
INJECTIONNUMBER, INJECTIONSTATUS
};
#define SimulationPending 0
#define SimulationInProgress 1
#define SimulationTerminated 2
#define SimulationError 3
Ui::ServerMTh *ui;
bool ForceAbort;
bool Disconnecting;
int return_value;
int NbrInjections, i_progress;
int maxOperativeThreads, InjectingThreads;
int TotalSimulations, SimulationsFinished, SimulationsInProgress;
int *InjectionStatus;
QThreadPool *ThreadPool;
QList<int> ErrorClients;
QElapsedTimer *timerStart, *timerStartSimulation;
qint64 EndOperationTime, EndSimulationTime;
void reject();
QString FormatTime
(const qint64
time);
};
#endif // SERVERMTH_H
#ifndef SERVERMTH_H
#define SERVERMTH_H
#include <QFile>
#include <QFileInfo>
#include <QDialog>
#include <QMessageBox>
#include <QProcess>
#include <QProgressDialog>
#include <QString>
#include <QStringList>
#include <QThreadPool>
#include <QElapsedTimer>
#include "BasicDeclarations.h"
#include "ClientRunnable.h"
namespace Ui {
class ServerMTh;
}
class ServerMTh : public QDialog
{
Q_OBJECT
public:
explicit ServerMTh(QWidget *parent = nullptr, QString designpath = "", QString design = "",
int nbr_injections = 0, QStringList *macro_list = nullptr,
QStringList *trace_list = nullptr);
~ServerMTh();
private slots:
void confirmAbort();
void ClientStarted(int id_client);
void ClientTerminated(int id_client, int client_status);
private:
enum
{
INJECTIONNUMBER, INJECTIONSTATUS
};
#define SimulationPending 0
#define SimulationInProgress 1
#define SimulationTerminated 2
#define SimulationError 3
Ui::ServerMTh *ui;
bool ForceAbort;
bool Disconnecting;
int return_value;
int NbrInjections, i_progress;
int maxOperativeThreads, InjectingThreads;
int TotalSimulations, SimulationsFinished, SimulationsInProgress;
int *InjectionStatus;
QString Design_Path, Design;
QStringList *macroList, *traceList;
QThreadPool *ThreadPool;
QList<int> ErrorClients;
QElapsedTimer *timerStart, *timerStartSimulation;
qint64 EndOperationTime, EndSimulationTime;
void reject();
QString FormatTime(const qint64 time);
int WriteTimeReport(QString fich);
};
#endif // SERVERMTH_H
To copy to clipboard, switch view to plain text mode
The two slots that should be invoked by the client are ClientStarted(int id_client) and ClientTerminated(int id_client, int client_status).
Server.cpp
#include <QDir>
#include <QTextStream>
#include "ServerMTh.h"
#include "ui_ServerMTh.h"
ui(new Ui::ServerMTh)
{
ui->setupUi(this);
// GUI and other elements setup
// 2. Create runnables and launch to threads
for (int i_injection = 0; (i_injection < TotalSimulations); i_injection++)
{
ClientRunnable *Client = new ClientRunnable(this);// The idea is that the client knows the "owner" of ths slots to invoke
Client->ID = i_injection;
Client->Design = Design;
Client->MacroFile = macroList->at(i_injection);
ThreadPool->start(Client);
}
}
ServerMTh::~ServerMTh()
{
}
void ServerMTh::confirmAbort()
{
ui->progressCancel->setEnabled(false);
QString msg
= "Abort injection. Are you sure?";
msgBox.setText(msg);
{
ui->progressInfo->setText("Please wait until injections in progress end...");
qApp->processEvents();
ThreadPool->clear();
ThreadPool->waitForDone(-1);
Disconnecting = true;
done(-1);
}
else
ui->progressCancel->setEnabled(true);
qApp->processEvents();
}
void ServerMTh::ClientStarted(int id_client)
{
// Update GUI
}
void ServerMTh::ClientTerminated(int id_client, int client_status)
{
// Check Modelsim start status
if (client_status == ClientRunnable::KOCLIENTSTART)
{
if (ErrorClients.contains(id_client))
{
// Same simulation has produced two errors => Terminate
ThreadPool->clear();
ThreadPool->waitForDone(-1);
Disconnecting = true;
done(-1);
}
else
{
// Add the task to the pool
ClientRunnable *Client = new ClientRunnable;
Client->ID = id_client;
Client->Design = Design;
Client->MacroFile = macroList->at(id_client);
ThreadPool->start(Client);
}
}
else
{
if (ErrorClients.contains(id_client))
{
// Remove erroneous simulation from the list
ErrorClients.removeAt(ErrorClients.indexOf(id_client));
}
// Update GUI
if ((TotalSimulations - (SimulationsFinished + SimulationsInProgress)) == 0)
{
ThreadPool->waitForDone(-1);
Disconnecting = true;
done(0);
}
}
}
void ServerMTh::reject()
{
if (!Disconnecting)
confirmAbort();
}
QString ServerMTh
::FormatTime(const qint64
time) {
return QString("%1:%2:%3").
arg((time / 3600000),
2,
10,
QChar('0')).
arg(((time / 60000) % 60),
2,
10,
QChar('0')).
arg(((time / 1000) % 60),
2,
10,
QChar('0'));
}
int ServerMTh
::WriteTimeReport(QString fich
) {
return 0;
}
#include <QDir>
#include <QTextStream>
#include "ServerMTh.h"
#include "ui_ServerMTh.h"
ServerMTh::ServerMTh(QWidget *parent, QString designpath, QString design, int nbr_injections, QStringList *macro_list, QStringList *trace_list) :
QDialog(parent),
ui(new Ui::ServerMTh)
{
ui->setupUi(this);
// GUI and other elements setup
// 2. Create runnables and launch to threads
for (int i_injection = 0; (i_injection < TotalSimulations); i_injection++)
{
ClientRunnable *Client = new ClientRunnable(this);// The idea is that the client knows the "owner" of ths slots to invoke
Client->ID = i_injection;
Client->Design = Design;
Client->MacroFile = macroList->at(i_injection);
ThreadPool->start(Client);
}
}
ServerMTh::~ServerMTh()
{
}
void ServerMTh::confirmAbort()
{
ui->progressCancel->setEnabled(false);
QString msg = "Abort injection. Are you sure?";
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Question);
msgBox.setText(msg);
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::Yes)
{
ui->progressInfo->setText("Please wait until injections in progress end...");
qApp->processEvents();
ThreadPool->clear();
ThreadPool->waitForDone(-1);
Disconnecting = true;
done(-1);
}
else
ui->progressCancel->setEnabled(true);
qApp->processEvents();
}
void ServerMTh::ClientStarted(int id_client)
{
// Update GUI
}
void ServerMTh::ClientTerminated(int id_client, int client_status)
{
// Check Modelsim start status
if (client_status == ClientRunnable::KOCLIENTSTART)
{
if (ErrorClients.contains(id_client))
{
// Same simulation has produced two errors => Terminate
ThreadPool->clear();
ThreadPool->waitForDone(-1);
Disconnecting = true;
done(-1);
}
else
{
// Add the task to the pool
ClientRunnable *Client = new ClientRunnable;
Client->ID = id_client;
Client->Design = Design;
Client->MacroFile = macroList->at(id_client);
ThreadPool->start(Client);
}
}
else
{
if (ErrorClients.contains(id_client))
{
// Remove erroneous simulation from the list
ErrorClients.removeAt(ErrorClients.indexOf(id_client));
}
// Update GUI
if ((TotalSimulations - (SimulationsFinished + SimulationsInProgress)) == 0)
{
ThreadPool->waitForDone(-1);
Disconnecting = true;
done(0);
}
}
}
void ServerMTh::reject()
{
if (!Disconnecting)
confirmAbort();
}
QString ServerMTh::FormatTime(const qint64 time)
{
return QString("%1:%2:%3").arg((time / 3600000), 2, 10, QChar('0')).arg(((time / 60000) % 60), 2, 10, QChar('0')).arg(((time / 1000) % 60), 2, 10, QChar('0'));
}
int ServerMTh::WriteTimeReport(QString fich)
{
return 0;
}
To copy to clipboard, switch view to plain text mode
Client.h
#ifndef CLIENT_RUNNABLE_H
#define CLIENT_RUNNABLE_H
#include <QObject>
#include <QProcess>
#include <QRunnable>
#include <QString>
class ClientRunnable : public QRunnable
{
Q_OBJECT
public:
enum
{
OKCLIENTSTART, KOCLIENTSTART
};
ClientRunnable
(QWidget *parent
= nullptr
);
int ID;
private:
int Status;
int CheckLog();
int FindTrace();
int CleanTrace();
protected:
void run();
};
#endif // CLIENT_RUNNABLE_H
#ifndef CLIENT_RUNNABLE_H
#define CLIENT_RUNNABLE_H
#include <QObject>
#include <QProcess>
#include <QRunnable>
#include <QString>
class ClientRunnable : public QRunnable
{
Q_OBJECT
public:
enum
{
OKCLIENTSTART, KOCLIENTSTART
};
ClientRunnable(QWidget *parent = nullptr);
int ID;
QString MacroFile, Design;
private:
QWidget *Parent;
QString LogFile, TraceFile;
int Status;
QProcess *proc;
int CheckLog();
int FindTrace();
int CleanTrace();
protected:
void run();
};
#endif // CLIENT_RUNNABLE_H
To copy to clipboard, switch view to plain text mode
Client.cpp
#include <QArgument>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QMetaObject>
#include <QStringList>
#include "ClientRunnable.h"
ClientRunnable
::ClientRunnable(QWidget *parent
){
Parent = parent;
Status = OKCLIENTSTART;
}
void ClientRunnable::run()
{
// Compìler error HERE:
QMetaObject::invokeMethod(Parent,
"ClientStarted", Qt
::QueuedConnection, Q_ARG
(int, ID
));
// Note that "Parent" is the server, that is, the owner of the slot invoked
// 1. Create process and run
pars << ...;
if (proc->execute("vsim.exe", pars) < 0)
Status = KOCLIENTSTART;
// 2. Check log file
if (Status == OKCLIENTSTART)
{
if (CheckLog() < 0)
Status = KOCLIENTSTART;
}
// 3. Compress trace file
if (Status == OKCLIENTSTART)
{
if (FindTrace() < 0)
Status = KOCLIENTSTART;
if (Status == OKCLIENTSTART)
{
if (TraceFile != "")
{
if (CleanTrace() < 0)
Status = KOCLIENTSTART;
}
else
Status = KOCLIENTSTART;
}
}
// Compìler error HERE too:
QMetaObject::invokeMethod(Parent,
"ClientTerminated", Qt
::QueuedConnection, Q_ARG
(int, ID
), Q_ARG
(int, Status
));
if (Status == OKCLIENTSTART)
exit(0);
else
exit(-1);
}
int ClientRunnable::CheckLog()
{
return 0;
}
int ClientRunnable::FindTrace()
{
return 0;
}
int ClientRunnable::CleanTrace()
{
return 0;
}
#include <QArgument>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QMetaObject>
#include <QStringList>
#include "ClientRunnable.h"
ClientRunnable::ClientRunnable(QWidget *parent)
{
Parent = parent;
Status = OKCLIENTSTART;
}
void ClientRunnable::run()
{
// Compìler error HERE:
QMetaObject::invokeMethod(Parent, "ClientStarted", Qt::QueuedConnection, Q_ARG(int, ID));
// Note that "Parent" is the server, that is, the owner of the slot invoked
// 1. Create process and run
QStringList pars;
pars << ...;
proc = new QProcess;
if (proc->execute("vsim.exe", pars) < 0)
Status = KOCLIENTSTART;
// 2. Check log file
if (Status == OKCLIENTSTART)
{
if (CheckLog() < 0)
Status = KOCLIENTSTART;
}
// 3. Compress trace file
if (Status == OKCLIENTSTART)
{
if (FindTrace() < 0)
Status = KOCLIENTSTART;
if (Status == OKCLIENTSTART)
{
if (TraceFile != "")
{
if (CleanTrace() < 0)
Status = KOCLIENTSTART;
}
else
Status = KOCLIENTSTART;
}
}
// Compìler error HERE too:
QMetaObject::invokeMethod(Parent, "ClientTerminated", Qt::QueuedConnection, Q_ARG(int, ID), Q_ARG(int, Status));
if (Status == OKCLIENTSTART)
exit(0);
else
exit(-1);
}
int ClientRunnable::CheckLog()
{
return 0;
}
int ClientRunnable::FindTrace()
{
return 0;
}
int ClientRunnable::CleanTrace()
{
return 0;
}
To copy to clipboard, switch view to plain text mode
Bookmarks