Cross Thread Signals not working
-
Hi,
I made this class (CanHandler) to take CAN frames and translate them using a DBC file. I then used another class (ThreadHandler) to make this class run in a seperate thread (CanThread) AND connected my emitting signals to functions running on the main thread. I could then, using QProperty, show these values on my qml App. This all worked.
Then I split up my CanHandler Class into 3 seperate classes and in the ThreadHandler class moved those to the CanThread. Now for some reason, the values aren't showing up on my qml app anymore. The "set_" function don't get called for some reason even though i connected them AND am emitting to the signals from the CanData class.
This code was the exact same for my first situation, but now 3 classes get put in the canThread instead of 1.
#ifndef THREADHANDLER_H #define THREADHANDLER_H #include <QObject> #include <QThread> #include "canraw.h" #include "cantranslation.h" #include "candata.h" class ThreadHandler : public QObject { Q_OBJECT Q_PROPERTY(double AccPedalPosition READ AccPedalPosition NOTIFY AccPedalPositionChanged) Q_PROPERTY(double BatteryLevel READ BatteryLevel NOTIFY BatteryLevelChanged) Q_PROPERTY(double EnginePercentLoadCurrentSpeed READ EnginePercentLoadCurrentSpeed NOTIFY EnginePercentLoadCurrentSpeedChanged) Q_PROPERTY(double EnginetorquePercentage READ EnginetorquePercentage NOTIFY EnginetorquePercentageChanged) Q_PROPERTY(double EngineSpeed READ EngineSpeed NOTIFY EngineSpeedChanged) public: explicit ThreadHandler(QObject *parent = nullptr) : QObject(parent) { canRaw->moveToThread(canThread); canTranslation->moveToThread(canThread); canData->moveToThread(canThread); connect(canThread, &QThread::started, canRaw, &CanRaw::init); connect(canThread, &QThread::started, canTranslation, &CanTranslation::init); connect(canThread, &QThread::started, canData, &CanData::init); connect(canData, &CanData::AccPedalPositionChanged, this, &ThreadHandler::set_AccPedalPosition); connect(canData, &CanData::BatteryLevelChanged, this, &ThreadHandler::set_BatteryLevel); connect(canData, &CanData::EnginePercentLoadCurrentSpeedChanged, this, &ThreadHandler::set_EnginePercentLoadCurrentSpeed); connect(canData, &CanData::EnginetorquePercentageChanged, this, &ThreadHandler::set_EnginetorquePercentage); connect(canData, &CanData::EngineSpeedChanged, this, &ThreadHandler::set_EngineSpeed); connect(canThread, &QThread::started, this, &ThreadHandler::canThreadFunction); canThread->start(); qDebug() << "CanThread running in thread:" << QThread::currentThread(); } ~ThreadHandler() { canThread->quit(); canThread->wait(); } double AccPedalPosition() const { return raw_AccpedalPosition; } double BatteryLevel() const { return raw_BatteryLevel; } double EnginePercentLoadCurrentSpeed() const { return raw_EnginePercentLoadCurrentSpeed; } double EnginetorquePercentage() const { return raw_EnginetorquePercentage; } double EngineSpeed() const { return raw_EngineSpeed; } public slots: void set_AccPedalPosition(double value) { qDebug() << "YES"; if (raw_AccpedalPosition != value) { qDebug() << "YES"; raw_AccpedalPosition = value; emit AccPedalPositionChanged(value); } } void set_BatteryLevel(double value) { qDebug() << "YES"; if (raw_BatteryLevel != value) { qDebug() << "YES"; raw_BatteryLevel = value; emit BatteryLevelChanged(value); } } void set_EnginePercentLoadCurrentSpeed(double value) { qDebug() << "YES"; if (raw_EnginePercentLoadCurrentSpeed != value) { qDebug() << "YES"; raw_EnginePercentLoadCurrentSpeed = value; emit EnginePercentLoadCurrentSpeedChanged(value); } } void set_EnginetorquePercentage(double value) { qDebug() << "YES"; if (raw_EnginetorquePercentage != value) { qDebug() << "YES"; raw_EnginetorquePercentage = value; emit EnginetorquePercentageChanged(value); } } void set_EngineSpeed(double value) { qDebug() << "YES"; if (raw_EngineSpeed != value) { qDebug() << "YES"; raw_EngineSpeed = value; emit EngineSpeedChanged(value); } } private: QThread *canThread = new QThread(); CanRaw *canRaw = new CanRaw(); CanTranslation *canTranslation = new CanTranslation(); CanData *canData = new CanData(); double raw_AccpedalPosition = 0.0; double raw_BatteryLevel = 0.0; double raw_EnginePercentLoadCurrentSpeed = 0.0; double raw_EnginetorquePercentage = 0.0; double raw_EngineSpeed = 0.0; signals: void AccPedalPositionChanged(double value); void BatteryLevelChanged(double value); void EnginePercentLoadCurrentSpeedChanged(double value); void EnginetorquePercentageChanged(double value); void EngineSpeedChanged(double value); }; #endif // THREADHANDLER_H
What could be the issue here?
-
Hi,
I made this class (CanHandler) to take CAN frames and translate them using a DBC file. I then used another class (ThreadHandler) to make this class run in a seperate thread (CanThread) AND connected my emitting signals to functions running on the main thread. I could then, using QProperty, show these values on my qml App. This all worked.
Then I split up my CanHandler Class into 3 seperate classes and in the ThreadHandler class moved those to the CanThread. Now for some reason, the values aren't showing up on my qml app anymore. The "set_" function don't get called for some reason even though i connected them AND am emitting to the signals from the CanData class.
This code was the exact same for my first situation, but now 3 classes get put in the canThread instead of 1.
#ifndef THREADHANDLER_H #define THREADHANDLER_H #include <QObject> #include <QThread> #include "canraw.h" #include "cantranslation.h" #include "candata.h" class ThreadHandler : public QObject { Q_OBJECT Q_PROPERTY(double AccPedalPosition READ AccPedalPosition NOTIFY AccPedalPositionChanged) Q_PROPERTY(double BatteryLevel READ BatteryLevel NOTIFY BatteryLevelChanged) Q_PROPERTY(double EnginePercentLoadCurrentSpeed READ EnginePercentLoadCurrentSpeed NOTIFY EnginePercentLoadCurrentSpeedChanged) Q_PROPERTY(double EnginetorquePercentage READ EnginetorquePercentage NOTIFY EnginetorquePercentageChanged) Q_PROPERTY(double EngineSpeed READ EngineSpeed NOTIFY EngineSpeedChanged) public: explicit ThreadHandler(QObject *parent = nullptr) : QObject(parent) { canRaw->moveToThread(canThread); canTranslation->moveToThread(canThread); canData->moveToThread(canThread); connect(canThread, &QThread::started, canRaw, &CanRaw::init); connect(canThread, &QThread::started, canTranslation, &CanTranslation::init); connect(canThread, &QThread::started, canData, &CanData::init); connect(canData, &CanData::AccPedalPositionChanged, this, &ThreadHandler::set_AccPedalPosition); connect(canData, &CanData::BatteryLevelChanged, this, &ThreadHandler::set_BatteryLevel); connect(canData, &CanData::EnginePercentLoadCurrentSpeedChanged, this, &ThreadHandler::set_EnginePercentLoadCurrentSpeed); connect(canData, &CanData::EnginetorquePercentageChanged, this, &ThreadHandler::set_EnginetorquePercentage); connect(canData, &CanData::EngineSpeedChanged, this, &ThreadHandler::set_EngineSpeed); connect(canThread, &QThread::started, this, &ThreadHandler::canThreadFunction); canThread->start(); qDebug() << "CanThread running in thread:" << QThread::currentThread(); } ~ThreadHandler() { canThread->quit(); canThread->wait(); } double AccPedalPosition() const { return raw_AccpedalPosition; } double BatteryLevel() const { return raw_BatteryLevel; } double EnginePercentLoadCurrentSpeed() const { return raw_EnginePercentLoadCurrentSpeed; } double EnginetorquePercentage() const { return raw_EnginetorquePercentage; } double EngineSpeed() const { return raw_EngineSpeed; } public slots: void set_AccPedalPosition(double value) { qDebug() << "YES"; if (raw_AccpedalPosition != value) { qDebug() << "YES"; raw_AccpedalPosition = value; emit AccPedalPositionChanged(value); } } void set_BatteryLevel(double value) { qDebug() << "YES"; if (raw_BatteryLevel != value) { qDebug() << "YES"; raw_BatteryLevel = value; emit BatteryLevelChanged(value); } } void set_EnginePercentLoadCurrentSpeed(double value) { qDebug() << "YES"; if (raw_EnginePercentLoadCurrentSpeed != value) { qDebug() << "YES"; raw_EnginePercentLoadCurrentSpeed = value; emit EnginePercentLoadCurrentSpeedChanged(value); } } void set_EnginetorquePercentage(double value) { qDebug() << "YES"; if (raw_EnginetorquePercentage != value) { qDebug() << "YES"; raw_EnginetorquePercentage = value; emit EnginetorquePercentageChanged(value); } } void set_EngineSpeed(double value) { qDebug() << "YES"; if (raw_EngineSpeed != value) { qDebug() << "YES"; raw_EngineSpeed = value; emit EngineSpeedChanged(value); } } private: QThread *canThread = new QThread(); CanRaw *canRaw = new CanRaw(); CanTranslation *canTranslation = new CanTranslation(); CanData *canData = new CanData(); double raw_AccpedalPosition = 0.0; double raw_BatteryLevel = 0.0; double raw_EnginePercentLoadCurrentSpeed = 0.0; double raw_EnginetorquePercentage = 0.0; double raw_EngineSpeed = 0.0; signals: void AccPedalPositionChanged(double value); void BatteryLevelChanged(double value); void EnginePercentLoadCurrentSpeedChanged(double value); void EnginetorquePercentageChanged(double value); void EngineSpeedChanged(double value); }; #endif // THREADHANDLER_H
What could be the issue here?
@MaximBozek said in Cross Thread Signals not working:
connect(canThread, &QThread::started, this, &ThreadHandler::canThreadFunction);
Your example does not even compile.
Please provide a minimal, compilable example or at least all relevant code pieces. Are you sure your init functions all work correct? -
@MaximBozek said in Cross Thread Signals not working:
connect(canThread, &QThread::started, this, &ThreadHandler::canThreadFunction);
Your example does not even compile.
Please provide a minimal, compilable example or at least all relevant code pieces. Are you sure your init functions all work correct?@Christian-Ehrlicher My bad, this line should not be in the program, I can't get you the full project till monday
-
@MaximBozek said in Cross Thread Signals not working:
connect(canThread, &QThread::started, this, &ThreadHandler::canThreadFunction);
Your example does not even compile.
Please provide a minimal, compilable example or at least all relevant code pieces. Are you sure your init functions all work correct?@Christian-Ehrlicher The init functions are working fine, but my main issue is that the signals form the CanData Class i am emitting, are not carrying out the functions from the ThreadHandler Class (those 5 connections i am making).
-
@Christian-Ehrlicher The init functions are working fine, but my main issue is that the signals form the CanData Class i am emitting, are not carrying out the functions from the ThreadHandler Class (those 5 connections i am making).
What do your CAN classes look like?
-
What do your CAN classes look like?
Tried sending the code in the text editor, got a spam warning. Tried sending a wetransfer link, got a spam warning> How should I send the code?
-
Tried sending the code in the text editor, got a spam warning. Tried sending a wetransfer link, got a spam warning> How should I send the code?
Try again using code tags here in the forum (the
</>
button)
I upvoted your comment. With increasing reputation the spam restrictions become less harsh -
Try again using code tags here in the forum (the
</>
button)
I upvoted your comment. With increasing reputation the spam restrictions become less harshTried even my smallest class and it was warning spam, here is only the source code from that class, the one where i emit the signals:
#include "candata.h" CanData::CanData(QObject *parent) : QObject(parent) {} void CanData::init() { qDebug() << "CanData running in thread:" << QThread::currentThread(); } void CanData::parseSignalValues(const QMap<QString, QVariant> &signalValues) { for (auto it = signalValues.cbegin(); it != signalValues.cend(); ++it) { QString signalName = it.key(); QVariant value = it.value(); qDebug() << signalName << ":" << value.toDouble(); if (signalName == "Acc_pedal_position1") { emit AccPedalPositionChanged(value.toDouble()); } else if (signalName == "Battery_Level") { emit BatteryLevelChanged(value.toDouble()); } else if (signalName == "Engine_Percent_Load_Current_Spd") { emit EnginePercentLoadCurrentSpeedChanged(value.toDouble()); } else if (signalName == "Actual_Engine_porcentage_torque") { emit EnginetorquePercentageChanged(value.toDouble()); } else if (signalName == "Engine_Speed") { emit EngineSpeedChanged(value.toDouble()); } } }
-
Tried even my smallest class and it was warning spam, here is only the source code from that class, the one where i emit the signals:
#include "candata.h" CanData::CanData(QObject *parent) : QObject(parent) {} void CanData::init() { qDebug() << "CanData running in thread:" << QThread::currentThread(); } void CanData::parseSignalValues(const QMap<QString, QVariant> &signalValues) { for (auto it = signalValues.cbegin(); it != signalValues.cend(); ++it) { QString signalName = it.key(); QVariant value = it.value(); qDebug() << signalName << ":" << value.toDouble(); if (signalName == "Acc_pedal_position1") { emit AccPedalPositionChanged(value.toDouble()); } else if (signalName == "Battery_Level") { emit BatteryLevelChanged(value.toDouble()); } else if (signalName == "Engine_Percent_Load_Current_Spd") { emit EnginePercentLoadCurrentSpeedChanged(value.toDouble()); } else if (signalName == "Actual_Engine_porcentage_torque") { emit EnginetorquePercentageChanged(value.toDouble()); } else if (signalName == "Engine_Speed") { emit EngineSpeedChanged(value.toDouble()); } } }
@MaximBozek said in Cross Thread Signals not working:
void CanData::parseSignalValues
Where / From where you call this function?
Also as @Christian-Ehrlicher said before, make sure everything is initialized correctly and you actually run your threaded workers (
canRaw
,canTranslation
andcanData
)... because just moving them won't start them...
and, for example yourCanData::init
void CanData::init() { qDebug() << "CanData running in thread:" << QThread::currentThread(); }
which is connected to
QThread::started
here:connect(canThread, &QThread::started, canData, &CanData::init);
does pretty much nothing :)
-
@MaximBozek said in Cross Thread Signals not working:
void CanData::parseSignalValues
Where / From where you call this function?
Also as @Christian-Ehrlicher said before, make sure everything is initialized correctly and you actually run your threaded workers (
canRaw
,canTranslation
andcanData
)... because just moving them won't start them...
and, for example yourCanData::init
void CanData::init() { qDebug() << "CanData running in thread:" << QThread::currentThread(); }
which is connected to
QThread::started
here:connect(canThread, &QThread::started, canData, &CanData::init);
does pretty much nothing :)
@Pl45m4 How would you run my workers in this case?
-
@Pl45m4 How would you run my workers in this case?
How should we be able to tell? It's your program and we can just see a tiny snippet. That's why I asked... so you can check it yourself.
Who callsCanData::parseSignalValues
?! From what we can see, it's called nowhere (or at least in a class that we can't see), that's why no signals are emitted.
Just moving the object to the new thread and starting the thread won't start the worker.Go through your code and check your logic... from the creation of all the workers to moving them to a new thread and connecting your signals...
-
How should we be able to tell? It's your program and we can just see a tiny snippet. That's why I asked... so you can check it yourself.
Who callsCanData::parseSignalValues
?! From what we can see, it's called nowhere (or at least in a class that we can't see), that's why no signals are emitted.
Just moving the object to the new thread and starting the thread won't start the worker.Go through your code and check your logic... from the creation of all the workers to moving them to a new thread and connecting your signals...
@Pl45m4 I am calling
CanData::parseSignalValues
somewhere in my code, but I can't really show this... This forum doesn't really allow long posts to be posted, unless you have the necessary reputation (?). This is a rough explaination:I while loop until the
vcan0
CAN device is connected to the program. Then I translate every CAN frame that comes in (CanTranslation
class). Then I send the parsed values (comes out of the translation as aQMap
array) toCanData::parseSignalValues
which splits up theQMap
array and emits every values seperately. This emit should trigger a function inside theThreadHandler
class, but it is not.Like i said in the initial post, this used to work, before I split up my initial class (
CanHandler
) in 3:CanRaw
,CanTranslation
andCanData
. -
@Pl45m4 I am calling
CanData::parseSignalValues
somewhere in my code, but I can't really show this... This forum doesn't really allow long posts to be posted, unless you have the necessary reputation (?). This is a rough explaination:I while loop until the
vcan0
CAN device is connected to the program. Then I translate every CAN frame that comes in (CanTranslation
class). Then I send the parsed values (comes out of the translation as aQMap
array) toCanData::parseSignalValues
which splits up theQMap
array and emits every values seperately. This emit should trigger a function inside theThreadHandler
class, but it is not.Like i said in the initial post, this used to work, before I split up my initial class (
CanHandler
) in 3:CanRaw
,CanTranslation
andCanData
.@MaximBozek said in Cross Thread Signals not working:
CanData::parseSignalValues
which splits up the QMap array and emits every values seperatelyDoes this work? Is this function actually called? This way you can check if it's a logical error in your code or some issue with the signal connection.
This forum doesn't really allow long posts to be posted, unless you have the necessary reputation (?)
Try something like pastebin if you don't mind sharing your code (at least more relevant bits) there.
-
@MaximBozek said in Cross Thread Signals not working:
CanData::parseSignalValues
which splits up the QMap array and emits every values seperatelyDoes this work? Is this function actually called? This way you can check if it's a logical error in your code or some issue with the signal connection.
This forum doesn't really allow long posts to be posted, unless you have the necessary reputation (?)
Try something like pastebin if you don't mind sharing your code (at least more relevant bits) there.
@Pl45m4 I just tried the exact same code, but all function in one class. THIS WORKS
When I split up my class,
CanData::parseSignalValues
was being called (checked with a simpleqDebug()
).CanData::parseSignalValues
is posted in reply #8 by the way.