How to access data from thread two, created in thread one
-
bq. The easiest and safest way is using the SIGNAL – SLOT mechanism. Emit a signal with your QByteArray as parameter in animation thread and connect to a slot taking a QByteArray as parameter in your sent thread.
Sounds promising, but there is a problem the animation generation takes some time because every animation waits at least ones for X milliseconds before it continues creating the next part of the animation, so in fact I have to emit a signal within the animation class
because when it returns to the animationThread the data are already X times overwritten. -
I get the following warning (error) on runtime.
@QObject::connect: Cannot queue arguments of type 'QByteArray&'
(Make sure 'QByteArray&' is registered using qRegisterMetaType().)
@How can I solve this!
-
I get this warning when calling the sendAnimations function in SendThread.
@QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0x151ecd0), parent's thread is QThread(0x14be8f0), current thread is QThread(0x7fff1a0dda50)
@What does that mean should I open the serial port in the SendThread instead in MainWindow class?
-
Hi,
bq. // In MainWindow
QByteArray *byteArray
aThread = animationThread(byteArray);
sThread = sendThread(serial,byteArray);That kind of construct is not safe at all.
Since you will be sending QByteArrays in your SenderThread, just emit one from your AnimationThread
-
Well, I cant emit from AnimationaThread (I think at least :-) ), from this class all animation are called which are in the class animation.
In each animation the wait function gets called at least ones.
where than I emit currently a signal connected to the SenderThread.I changed QByteArray to QVector< QVector<uint8_t> >
That's how I do it right now
@// in MainWindow create connection
connect(playAction,&QAction::triggered,animationThread,&AnimationThread::createAnimations);
connect(animations,&Animations::dataChanged,sendThread,&SendThread::sendAnimations);
// How the worker threads are right now created
animations = new Animations;
animations->moveToThread(&aThread);
animationThread = new AnimationThread(animations);
animationThread->moveToThread(&aThread);
aThread.start();
serial->moveToThread(&sThread);
sendThread = new SendThread(serial);
sendThread->moveToThread(&sThread);
sThread.start();
@@ // In animationThread call animation from class animation
animationFirework(....);
@@// in the animation class
void animationFirework(...)
{
...
wait(ms);
....
wait(ms);
}void wait(uint16_t ms)
{
emit dataChanged(cubeVec); // void dataChanged(QVector< QVector<uint8_t> > &cubeVec)
timer->start(ms)
while(timer->isActive());
}
@@ // in class SenderThread
void SendThread::sendAnimations(QVector< QVector<uint8_t> > &data)
//void SendThread::sendAnimations()
{
// QReadLocker locker(&lock);// while(true){
m_serial->putChar(0xFF);
m_serial->waitForBytesWritten(1000);
m_serial->putChar(0x00);
m_serial->waitForBytesWritten(1000);
for (int z = 0; z < CUBE_SIZE; z++) {
for (int y = 0; y < CUBE_SIZE; y++) {
m_serial->putChar(data[z][y]);
m_serial->waitForBytesWritten(1000);
if(data[z][y] == 0xFF){
m_serial->putChar(0xFF);
m_serial->waitForBytesWritten(1000);
}
}
}
if (m_stoped)
return;
// m_running = true;
}
@And get the following warrning(error)
QObject::connect: Cannot queue arguments of type 'QVector<QVector<uint8_t> >&'
(Make sure 'QVector<QVector<uint8_t> >&' is registered using qRegisterMetaType().) -
Ok the problem with qRegisterMetaType() is solved
-
You can also Mutexes / ReadWriteLocks to guard your data.
I suggest creating a helper template class, something like "GuardedData<class T>". In there you have your actual data member of type T, and a ReadWriteLock. You only provide two public methods, "T get()" and "set(T val)". Inside the get()mMethod, you lock the ReadWriteLock for reading, and inside the set()-method, you look it for writing...
Having this helper-class, you could easily create a "GuardedData<QByteArray> m_guardedByteArray" member, that both threads can use. Via the ReadWriteLock, accesses are safe (and serialized).
There can obviously be a performance penalty, but depending on the size of your data and the frequency of access, it might not be noticable at all...
You can of still use the signal-slot-approach...
-
I have created this struct in a global header file and want to use it for singal and slots. But it does not work!
In Global.hpp
@typedef struct{
QString name;
QString text;
uint8_t id;
uint8_t particle;
uint16_t speed;
uint16_t delay;
uint16_t leds;
uint16_t iteration;
Direction direction;
Axis axis;
Bool invert;
BixelState state;
}AnimationStruct;
Q_DECLARE_METATYPE(AnimationStruct)@In MainWindow.cpp
@ qRegisterMetaType<AnimationStruct>("AnimationStruct");@
Error:
@ no matching function for call to 'QObject::connect(const Object*&, void (MainWindow::&)(const AnimationStruct&), const Object&, void (AnimationThread::*&)(const AnimationStruct&), Qt::ConnectionType)'
return connect(sender, signal, sender, slot, Qt::DirectConnection);invalid use of incomplete type 'struct QtPrivate::QEnableIf<false, QMetaObject::Connection>'
declaration of 'struct QtPrivate::QEnableIf<false, QMetaObject::Connection>'
template <bool B, typename T = void> struct QEnableIf;
@EDIT: Solved
-
bq. There can obviously be a performance penalty, but depending on the size of your data and the frequency of access, it might not be noticable at all…
Well I have currently massive performance problems using signal ans slots.
The CPU usage is > 25% and the animation are played slower than the microcontroller would do. -
I probably know why there is such a huge performance problem, there is anywhere in my Threads a massive memory leak.
When I start the application it needs 14kB memory, when I start the animation Thread and sending Thread. The memory usage climbs over 1GB within 10-30 seconds :-( !
I dont understand it.