Sending objects as signal arguments between threads in Qt - c++

I am new to Qt and trying to learn the Qt threading mechanism. I am in a situation where I would like a background thread to perform some long running task and report the results to another (or main) thread after processing every 100 items. Right now I am doing this by emitting a signal from the background thread containing a list of the processed objects that is received in a slot in the main thread. Does Qt make a copy of the signal argument when it is received in the slot ? If so, how does how does calling qRegisterMetaType help with that ? This is what I am tying to accomplish in my code :
//background thread
void run(){
//get a query object from database
int fireCount = 0;
QList< QList<QVariant> > data;
while(query->next()){
fireCount++;
QList<QVariant> row;
//do some calculations on the fields read from the query
processRow(query,&row);
data.append(row);
if(fireCount>100){
emit publishDataToMainThread(data);
fireCount = 0;
data.clear();
}
}
}
//slot in main thread
void receiveData(QList< QList<Qvariant> > data){
\\display the data
}
Also , is this a recommended practice for transferring objects between threads ?

This is a perfectly fine way of doing it. QList uses implicit sharing (i.e. copy on write) so copying it means copying one pointer and increasing the reference count. It only gets copied once you try to modify it.
Just remember to use Qt::QueuedConnection when connection the signal to the slot so that the slots gets run in the receivers thread.
qRegisterMetaType or Q_DECLARE_METATYPE are needed so that you can pass parameters by value in signals. It tells the Qt Metatype system (which is sort of like reflection) that this type exists.

Related

create `wxThread` to call backend function for every `EVT_TREELIST_ITEM_EXPANDED` event

I have following classes:
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_TREELIST_ITEM_CHECKED(wxID_ANY, MyFrame::OnItemChecked)
EVT_TREELIST_ITEM_EXPANDED(wxID_ANY, MyFrame::OnItemExpand)
END_EVENT_TABLE()
class MyThread: public wxThread
{
public:
MyThread(MyFrame *frame, wxTreeListItem &item);
virtual void *Entry();
SeleSyncFrame *m_frame;
wxTreeListItem item;
};
class MyFrame
{
friend class MyThread;
private:
wxTreeListCtrl* m_treelist;
public:
void OnItemExpand(wxTreeListEvent& event);
};
I have to update m_treelist on every EVT_TREELIST_ITEM_EXPANDED event. For that I am calling OnItemExpand().
void MyFrame::OnItemExpand(wxTreeListEvent& event)
{
wxTreeListItem item = event.GetItem();
MyThread *thread = new MyThread(this, item);
if (thread->Create() != wxTHREAD_NO_ERROR)
{
dbg.Error(__FUNCTION__, "Can't create thread!");
}
thread->Run();
}
constructor of MyThread class:
MyThread::MyThread(MyFrame *frame, wxTreeListItem &item) : wxThread()
{
m_frame = frame;
this->item = item;
}
Entry function of MyThread:
wxThread::ExitCode MyThread::Entry()
{
wxTreeListItem root = m_frame->m_treelist->GetRootItem();
m_frame->m_treelist->CheckItem(root, wxCHK_CHECKED);
//This back-end fun is time consuming
Calltobackend(string resp);
// I have to convert this string resp into xml and append all items of xml as children for 'item'.
(m_frame->m_treelist)->AppendItem(item, "child");
m_frame->m_treelist->CheckItem(item, wxCHK_CHECKED);
m_frame->m_treelist->UpdateItemParentStateRecursively(m_frame->m_treelist->GetFirstChild(item));
return NULL;
}
I want to create thread for every browse request and update corresponding item with its children. Is my approach is not correct? How should I achieve this? I was thinking of one more approach where I will use thread only to send request to backend and I will send response to Main thread using OnWorkerEvent. But I have to update item which is expanded with response returned by backend. How will that OnWorkerEvent will know which item from tree it has to update with children returned by response?
As VZ said, updating GUI from a different thread is a can of worms. Don't do it.
For your issue. Let's say you have to update a control (in your case, items of a treelist) with values that come from a long task.
The idea is simple:
On your user event handler (like OnItemExpand) just create and run
the thread. Don't wait for it, make it "detached".
In the thread code, just before it ends, post a message to the main thread by wxQueueEvent(). The value you need may be part of this message. Or
you can also write an accesible var, better using wxMutex; and use
the message to inform the main thread that that var is updated.
Write a new function (e.g. a MyFrame::OnMyThreadEnds) than handles the message and/or var. Here is where you update the GUI.
See http://docs.wxwidgets.org/trunk/classwx_thread.html
You can only use GUI objects from one (usually main) thread of your application, so your approach simply can't work. It's also not clear at all why would you go to the trouble of creating a thread just for doing this, it's not like there are any time-consuming operations being done in the thread here.
The standard way to use threads in GUI applications is to perform any long-running tasks in background worker threads and post events to the main thread to perform the GUI updates. You should structure your application like this unless you have really good reasons not to do it.
In more details, the traditional way to do it is for the worker thread to post wxThreadEvents to the main thread, containing the information that the main thread needs to perform the action. Notice that wxThreadEvent has SetPayload() method which allows you to pass any kind of data between threads, so you just need to call it in the worker and then use GetPayload() in the main thread to extract the information and process it.
However since wxWidgets 3.0 you have another way to do it with CallAfter(), which is especially convenient if you use C++11 (and you really should). This allows you to write the code you want to execute in the scope of the thread function, but it will actually get executed in the context of the main thread. So you could do this:
wxThread::ExitCode MyThread::Entry()
{
wxGetApp().CallAfter([this] {
wxTreeListItem root = m_frame->m_treelist->GetRootItem();
m_frame->m_treelist->CheckItem(root, wxCHK_CHECKED);
});
...
}
and it would actually work because the code inside the lambda would be run in the main thread. This is extremely convenient and you should do it like this, but just make sure you actually understand what does this do and that it still uses the same underlying mechanism of posting events to do its magic.

Corrupt QImage after a signal/slot call between two different threads

I am sending a QImage via a signal/slot mechanism, between two threads (a background DB thread and a GUI thread). The GUI slot receives a corrupt image (some pixels are randomly corrupt). I have done this already, and never had any issue. What could be wrong?
The programm is too complex to be included here, but here is some relevant information:
The sending thread (DB) is a regular QThread, with an event loop, running a DataBaseInterface QObject class which was moved to this thread
The signal/slot connection was done after the moveToThread, so each object is in its final thread. This means that explicitely using QueuedConnection makes no difference as this is already the case.
The QImage is not sent directly in the signal/slot parameters, but within a struct which contains other stuff (three QVectors). This struct was registered using:
qRegisterMetaType<MyStruct>("MyStruct");
The QImage was not created using an external buffer, but with the (width, height, Format) constructor. So the image buffer is maintained internally and thus implicitely shared
If I save the image to disk in the DB thread just after emitting the signal, it is good. If I save it just at the beginning of the slot, it is corrupt.
Any idea?
Thanks!
Ok, o that the image is not corrupted you should ensure the following:each data containing the structure that are sending must have copy constructor, avoids sending data pointer and if you do it sure that these reside in memory heap, the connection type for these cases is Qt::QueuedConnection, the label on establish the image that you think should be configured as follows:
label->setBackgroundRole(QPalette::Base);
label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
label->setScaledContents(true);
the slot where the image or comes your structure should look like this, in my case with opencv and QT is:
void interfaz::actImagenFromVideo(cv::Mat myImage)
{
QImage image(myImage.data,myImage.cols, myImage.rows, myImage.step, QImage::Format_RGB888 );
label->setPixmap(QPixmap::fromImage(image.rgbSwapped()));
}
he run function of your QThread should look something like:
void THREAD::run()
{
while(true){
{
QMutexLocker locker(&mutex);
if (stopped) {
stopped = false;
break;
}
}
cap>>videoIn;
emit image_ready(videoIn.clone()); //the use of cv::Mat::clone() is very important in openCV
}
}

Qt process events

I have a QString object which is exported to qml. In C++ code while updating the value and emitting the changed signal for the property it does not update it because thread is busy: in that time I use a cost-operation in for loop. For that purpose I use QCoreApplication::processEvents() to be able to emit delayed signals on each iteration of the loop like:
foreach(const QVariant& item, _manifestFile) {
setStatusString(QString("Checking file %1 of %2...").arg(currentProcessingFile++).arg(totalFilesCount));
QCoreApplication::processEvents(); // TODO remove
//...
}
Where setStatusString is setter of my QString variable I described above:
void Updater::setStatusString(const QString &statusString) {
_statusString = statusString;
emit statusStringChanged();
}
How can I remove that processEvents() and be able to emit signals? Any solution is appreciated: threaded, Qt-meta object things, etc.
You should create your object of the class Updater on the heap and move it to a new thread in order to prevent the for loop from blocking main thread and the UI. This can be done like:
updater = new Updater();
QThread * th = new QThread();
updater->moveToThread(th);
QObject::connect(th,SIGNAL(started()),updater,SLOT(OnStarted()));
QObject::connect(th,SIGNAL(finished()),updater,SLOT(OnFinished()));
QObject::connect(updater,SIGNAL(statusStringChanged(QString)),this,SLOT(updateString(QString)));
th->start();
Your initialization and termination tasks in the class Updater should be done in OnStarted() and OnFinished() slots respectively.
Now you can emit the signal with the appropriate value which would be queued and processed in the appropriate time. You can emit the signal in a timer periodically in certain intervals to prevent from emitting too frequent.
And the last point is that you should not call Updater functions directly when it is in an other thread. The correct way is defining the functions as slots and connecting a signal to that slot and emitting the signal when you want to call a specific function.

QtConcurrent mapped and progress report

I'm using QtConcurrent to do some heavy background image processing and I want to display the image while parts of it are being updated progressively.
Each line of the image is computed separately and is passed a functor.
To compute the full image I then have a sequence of item that I pass to QtConcurrent mapped and each line emits a signal when it is done computing
Here is the instantiation of the class Worker:
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
Here is the slot to report progress:
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
Now the usage:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
All the signals are emitted but the slot onProgressUpdate gets called only when Qtconcurrent::mapped is done with all the items in the sequence.
When executing it has a huge delay while the sequence is processing and then all slots are executed sequentially afterwards.
I have tried all types of signal/slots connection and none of them changed this behaviour.
Any clue ?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Shf suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The call was made until now in the main(gui) thread.
I changed the call to :
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
Since _computeTreeForFrame is now executed in another thread, I changed the call to QtConcurrent::mapped to:
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
This results in exactly the same behaviour as before.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Marek R suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ok so I made so tests and here is what I observed:
QtConcurrent::map :
Doesn't emit the signal resultReadyAt(int)
QtConcurrent::mapped
Emits resultReadyAt(int) only when finished
It doesn't matter if the call to the map function is done in a separate thread the same behaviour is encountered.
I also gave a try to the signal progressValueChanged(int) as the Qt progressDialog example suggests.
The signal progressValueChanged(int) gets emitted only for 2 lines in the image (the first and last).
This is really weird as in the Qt progress dialog example it is emitted smoothly.
I changed a bit the Qt example to launch the map function in another thread than the main thread and it still works well in that case.
The issue must arise from somewhere else.
Maybe the GUI event loop is doing something I don't expect ? I have no clue what.
I will now try QtConcurrent::mappedReduced and report with the results :-)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after giving a try to QtConcurrent::mappedReduced
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
It doesn't work and calls the "reduce" function ONLY when the "map" function is done. In other words it does the same than the previous signal/slots mechanism.
I'm running low in possibilities now
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT I'm back to a solution as close as the Qt progress dialog example
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Something must be wrong if I can't get the same behaviour than the Qt example.
Here's the code now:
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
The call to computeTreeForFrame...
...
_worker->computeTreeForFrame();
...
This call is done in a slot .
It emits the signals for the line 0 and for the last line as told before but doesn't emits anything else.
Shouldn't this do EXACTLY what the Qt example does?
From task description it looks like you should use mappedReduced. Problem is that I don't see a good way to get partial results. One way to overcome this problem is to emit signal form reduce function.
It is possible that this thread may help.
It seems, that QtConcurrent::mapped does not put VideoEngine::metaEnginePerRow in another thread, judging by the documentation. If image is processed in the same thread as GUI, then your slots indeed will be executed after processing, no matter what type of connection you select, just as you've described.
The solution is to either run Worker::_computeTreeForFrame (as i understood, your main processing function) in another thread via QtConcurrent::run or to put your Worker object in another thread probably via QObject::moveToThread(). Then, the connection type you should use is Qt::QueuedConnection (or if you will put Worker in another thread before connection, you can connect even with Qt::AutoConnectionor Qt::UniqueConnection, caller and receiver will be in a different threads, so qt will automaticly chose QueuedConnection`)
EDIT:
I'm not sure, but your _watcher = new QFutureWatcher<bool>; is still created in the main thread and if you call
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
would _watcher set GUI thread to wait, in what it was created or thread, where this command is executed. If _watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output))); if the end of a function, is _watcher->waitForFinished(); needed at all? Qt will destroy thread right after it's execution and you set your processing function to run, why wait?
And _computeFrameWatcher should be of QFuture<void*> type.
EDIT2:
Ok, before i give up, i suggest you to test QObject::moveToThread:
before you call _worker->computeTreeForFrame(); , put it in another thread:
QThread *workerThread=new QThread();
_worker->moveToThread();
_worker->computeTreeForFrame();
/* connect _worker's finished signal with workerThread::quit and deleteLater slots */
and all connections within _worker should be DirectConnection and all connections between _worker and main (GUI) thread should be connected with QueuedConnection. Also it's probably good to create new thread in _worker constructor and move it to another thread immediately, this way you can destroy thread in _worker's destructor and don't worry about thread problem's in GUI thread

qt signals/slots in a plugin

I have an app with such structure: all the datatypes (class INode) are stored in plugins (DLLs). Some of the datatypes can be drawn (if they're IDrawable).
To load an object of, e.g. class PointCloudNode: public INode I have a special input plugin (DLL) which is called class PointCloudParser: public IIOPlugin and IIOPlugin is a thread with some specific functionality: class IIOPlugin: public QThread.
All the objects are created by NodeFactory class which is a singleton stored in separate DLL.
And here's the problem:
void PointCloudNode::update()
{
QObject::connect (this,SIGNAL(tmptmp()),this,SLOT(drawObject()));
emit tmptmp();
}
If I do this from any thread (main thread or the Input Plugin thread)
NodeFactory* fab = NodeFactory::getInstance();
boost::shared_ptr<INode> pc(fab->createNode("pointCloud","myPC"));
boost::shared_ptr<IDrawable> dr = boost::dynamic_pointer_cast<IDrawable>(pc);
dr->update();
The update launches, the tmptmp() signal is emitted, and the slot (drawObject()) executes correctly.
BUT
if do just the same, but create the object in my Input Plugin, pass over the shared pointer and execute dr->update() in another function, the slot drawObject() is never entered though all the code is executed (including connect, etc.).
To be more precise, here's the Input Plugin:
void PointCloudParserPlugin::doLoad(const QString& inputName, boost::shared_ptr<INode> container)
{
NodeFactory* factory = NodeFactory::getInstance();
boost::shared_ptr<INode> node = factory->createNode("pointCloud", inputName);
// here goes the loading itself, nothing special...
container->addChild(node); //that's the container where I keep all the objects
//boost::dynamic_pointer_cast<IDrawable>(container->getChild(inputName))->update();
//If I uncomment this line, it all works: the slot is launched.
emit loadingFinished(inputName); // it executes the following function
}
The last emit is connected to this:
void GeomBox::updateVisualization(const QString& fileName)
{
boost::shared_ptr<INode> node = container_->getChild(fileName);
boost::shared_ptr<IDrawable> nodeDrawable = boost::dynamic_pointer_cast<IDrawable>(node);
nodeDrawable->update(); //this is the problem line: update() executes, connect() works, but the slot never runs :(
}
How come? The node object is the same all the way through, it is valid. Every line in code in launched, QObject::connect doesn't write anything to debug window, the signal tmptmp() is emitted, but the slot drawObject() in one case is never reached? Any ideas?
Upd.: If I do not inherit IIOPlugin from QThread, everything works fine (i.e. load the object in the main thread). I expected the signals/slots to work across the threads...
Since you are sending a signal across to a different thread, you might need to explicitly tell Qt that the connection should be a queued one:
QObject::connect(this, SIGNAL(tmptmp()), this, SLOT(drawObject()), Qt::QueuedConnection );
By default Qt will use Qt::AutoConnection as that last parameter, and it will choose whether to use a direct connection (if the slot is in the same thread as the emitter) or a queued connection (if the slot is in a different thread). But since your thread is in a separate library, maybe Qt isn't making the right assumption here.