PDA

View Full Version : Emitting a signal is corrupting data



pan
6th July 2011, 09:54
I am creating a "new" struct object and sending the pointer through a signal about 100 times per second. This signal is connected to a slot in a different thread. If I run the app with the first code snip-it, the data is corrupted between 0 and 10 000 sent signals. If I run it with the second code snip-it (I just wanted to do a little debugging) it never gets corrupted.

Any Ideas why this is happening? and if there is a nicer solution than using a conditional statement?

Corrupted after some time:


struct MyStruct
{
MyStruct(unsigned int handle, std::string const& aName, std::string const& bName) :
_handle(handle),
_aName(aName),
_bName(bName)
{
}

unsigned int _handle;
std::string _aName;
std::string _bName;
};


Doesn't get corrupted:


struct MyStruct
{
MyStruct(unsigned int handle, std::string const& aName, std::string const& bName) :
_handle(handle),
_aName(aName),
_bName(bName)
{
if(_bName.at(0) < 'A' || _bName.at(0) > 'z')
{
qDebug() << "ERROR: " << _bName.c_str();
}
if(_aName.size() > 0 && (_aName.at(0) < 'A' || _aName.at(0) > 'z'))
{
qDebug() << "ERROR: " << _aName.c_str();
}
}

unsigned int _handle;
std::string _aName;
std::string _bName;
};

MarekR22
6th July 2011, 10:01
You have problem with multi-threading! You did something wrong there but you didn't show anything about that so it is impossible to say what is wrong.

pan
6th July 2011, 10:25
Possibly, that is what I was trying to debug initially, but why would an "if" statement fix the problem?

In the slot I do this:

void Outer::receiveStruct(MyStruct *mStruct)
{
QWriteLocker locker(&lock);
_mStructs.push_back(mStruct);

}

lock is: mutable QReadWriteLock lock;

Then the objects are taken like so:


std::list<MyStruct *> Outer::getStructs()
{
QReadLocker locker(&lock);
std::list<CafRequest*> tmpList = _mStructs;
_mStructs.clear();
return tmpList;
}


I used to do this but it didn't seem to make any difference:


std::list<MyStruct *>* Outer::getStructs()
{
return &_mStructs;
}


The function that calls getStructs deletes the objects.

MarekR22
6th July 2011, 13:43
Still this gives almost nothing.
At least it seems you did something wrong.
Emitting and reciving in slot a pointer value is disturbing solution especially in mutithreding case.
I also suspect that you are using lock in wrong way.

The safest way to solve mutithreading producer consumer problem in Qt is:
Define QObjects class representing producer and consumer (do NOT subclass QThread!!!).
Create needed QThreads and move instances of producer (QObject::moveToThread (http://doc.qt.nokia.com/latest/qobject.html#moveToThread)) and consumer to proper threads.
Connect signal of producer to respective slot of consumer.
To pass by value custom structure by a signal slot mechanism declare and define meta data for this custom type (instruction can be found in documentation).
Use of default Qt type is recommended (QList, QVector insted std::list and std:vector).
Note that consumer should be faster then producer or event queue of consumer may grow.

pan
6th July 2011, 15:44
Thanks for your reply MarekR22, its much appreciated.

I can't give you all the code, I've just tried to break it down and was asking for ideas on what I saw as the main problem. I have done most of what you suggested, apart from what I have noted below.


Emitting and reciving in slot a pointer value is disturbing solution especially in mutithreding case.
I will try sending variables rather than a pointer.


Use of default Qt type is recommended (QList, QVector insted std::list and std:vector).
I'm using c++ types here in the application as they are used by a controller written in pure c++.


I also suspect that you are using lock in wrong way.
I originally used a mutex lock but found in the documentation that this is the way to do it, so just copied that method.


Note that consumer should be faster then producer or event queue of consumer may grow.
There is sort of a looping of signals and slots between the two threads, one does not emit more signals than it receives from the other, this should stop and event queue growing too much I would think.

pan
6th July 2011, 19:36
Actually that last statement I made is not true. I emit a lot of signals from my outer thread at the gui thread without requesting them first. Can I track them in the gui thread or just flush them occasionally?

pan
7th July 2011, 08:22
Hi

I now emit the data as int and QString from the Gui thread, my slot in the other thread converts the Qt types to c++ types. Now only the outer thread handles the struct creations and deletions. I thought that perhaps there would be less traffic passing a pointer, but if it is unstable then I can't use it.

This has now run 16 hours without problems.

Thanks heaps MarekR22!