Update Scene from Thread? - multithreading

I need to update a QGraphicsView with a QGraphicsScene from a thread.
Below is some pseudo'ish code example of what I am doing which is causing me issues (runtime errors).
What am I doing wrong, and how should I be doing it?
Main App:
void Main::startThread()
{
view = new QGraphicsView(...);
thread = new MyThread(...);
connect(thread, SIGNAL(doSceneUpdate(QGraphicsScene*)), this, SLOT(updateScene(QGraphicsScene*)));
thread->start();
}
void Main::updateScene(QGraphicsScene *scene)
{
view->SetScene(scene);
view->show();
repaint();
}
The Thread:
void MyThread::run()
{
QGraphicsScene *scene = new QGraphicsScene(...);
while(1)
{
//draw stuff on the scene
emit doSceneUpdate(scene);
//some delay
}
Thanks in advance!!!
[edit]
The error is:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread
3e53c0. Receiver '' (of type 'QGraphicsScene') was created in thread 1476cd18", file c:\Qt\qt-everywhere-opensource-src-4.8.2\src\corelib\kernel\qcoreapplication.cpp, line 501

What am I doing wrong, and how should I be doing it?
I think the canonical answer is here -- in a nutshell, the article states that you shouldn't be subclassing QThread, but rather you should use a "bare" (i.e. not-subclassed) QThread object and connect its started() signal to a slot that will then be run in the context of that thread, after the thread starts. That way the object-thread-ownership issues are handled automatically for you.
Note also that threads other than the main Qt thread are generally not allowed to create or interact directly with GUI objects like QGraphicsScene, since doing that would introduce race conditions due to the operations going on simultaneously behind the scenes in Qt's GUI event loop. If you want to use a separate thread, you'll need to keep it away from your GUI objects, and instead just have it emit asynchronous signals and/or send Events to the main/GUI thread to get the main/GUI thread to do the GUI-object updates on its behalf.

The problem is with your connection line. You are connecting a slot to a signal which does not make sense. You should connect the signal from the thread to the slot :
connect(thread, SIGNAL(doSceneUpdate(QGraphicsScene*)),this, SLOT(updateScene(QGraphicsScene*)));

in
void MyThread::run()
{
QGraphicsScene *scene = new QGraphicsScene(...);
...
}
do you pass this to the constructor of QGraphicsScene()?
That could be one cause of error, since now you are passing a child of MyThread to Main
Try creating a QGraphicsScene object on the stack or with the parent as NULL ( new QGraphicsScene(0) )

Related

QSerialPort in QThread run bytesAvailable is zero

Have a simple Qt app. Gui thread, creates Dev thread it creates (in its run()) Read thread. Dev and Read threads are my classes inherited from QThread. The Read thread should read data from COM port continuously. An approximate view of Read run is following.
read::run()
{
sp2->clear();
while (DO_EXEC)
{
if (DO_WRITE)
{
// write data to port
}
usleep(500);
ba = sp2->bytesAvailable();
if (ba > 0)
{
int a = sp2->read(&BUF[BUF_END], ba);
// process data
emit sgnl(sendeddata);
}
}
}
To start it I emit signal in GUI that is passed to Dev at it is passed to the following read slot:
read::slot_readStart()
{
// some stuff
if (doStart && !isRunning())
{
sp2 = new QSerialPort(this);
sp2->setPortName("COM3");
sp2->setBaudRate(256000);
sp2->setDataBits(QSerialPort::Data8);
sp2->setStopBits(QSerialPort::OneStop);
sp2->setParity(QSerialPort::NoParity);
sp2->setFlowControl(QSerialPort::NoFlowControl);
sp2->setReadBufferSize(5000);
bool isOpen = sp2->open(QIODevice::ReadWrite);
DO_EXEC = true;
start();
}
}
This works. But, if I place creating and setup and opening serial port to run method, then the port is open, but the bytesAvailable() are always zero? Why it is possible?
Thank you in adcance.
I agree with Orest Hera, in that you are using a "non recommended" way of implementing threads.
You are using inheritance for your thread object.
It is important to understand how QThreads work. The general procedure to using the QThreads is:
Make Object to go into thread, assign no parent
Make thread
Move object into thead using obj->moveToThread(thread)
Connect a signal to a slot in the object that will instatiate the object members (if required)
Start the thread: thread->start()
For example:
MyObj *myObj = new MyObj(0); // 0 = no parent if your object inherits QObject
QThread* thread = new QThread;
myObj->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), myObj, SLOT(run()));
thread->start();
So your object can still have its "run()" function, but it won't be overloading anything.
Also your run() function does not need to be a "forever" loop, it is simply an initialization function (create the serial port or whatever). Then you add other slots for other events, e.g. you can connect the QSerialPort::readyRead() to your "incoming data slot" handler to handle any data received from the serial port.... and so on.
I think this will solve your issues. It is difficult to tell exactly why your serial port does not work in your overloaded "Run()" function because I can't see how you are calling /creating the thread (i.e. the rest of your code) or where DO_EXEC is initialized etc... There is probably some ordering of events or thread ownership issue here.
Note: I am not saying you can't inherit thread class, but if you do that it is so that you create your own custom thread class (to do thread stuff), but not some other class to create a hybrid of thread utility and other stuff. There is a fair amount of information relating to this here (on SO) and on the qt forum if you are interested in the why/how etc... :)

Qt- How to streamline application by executing a resource intensive task in a different thread

I am creating a music library app using Qt( C++). It involves a method that does the following jobs in the given sequence-
List N audio files by recursively traversing a directory.
Read each and every file to collect ID3 tags.
Extract artwork images from the files.
Save the ID3 tags in the database.
The above set of tasks are extremely resource intensive. For N ~ 1000, it takes around a minute and half to complete the tasks and during the course of execution of this sequence, the GUI freezes up and doesn't respond well as I currently use no other threads.
I have seen a few examples of Qt threading and they more or less tell how to do things in parallel as expected but in those examples, achieving parallelism or concurrency is a requirement as they don't have any other options. But in case of my app, it's a choice whether I use multiple threads or not. The goal is to make sure the GUI stays responsive and interactive during the execution of the resource intensive task.I would really appreciate any expert advice may be with a code template or example in Qt to perform the resource intensive task in a different thread.
Code in main thread-
QStringList files;
QString status;
createLibrary(files, status); //To be done in a different thread
if(status == "complete"){
//do something
}
Thanks a lot your time!
You could use the QtConcurrent module.
Use QtConcurrent::map() to iterate over the list of files and call a method in separate thread:
QFuture<void> result = QtConcurrent::map(files, createLibrary);
QFutureWatcher will send a signal when the processing is done:
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()),
this, SLOT(processingFinished()));
// Start the computation.
QFuture<void> result = QtConcurrent::map(files, createLibrary);
watcher.setFuture(result);
BTW because of a lot of bad files in the wild, the music player Amarok decided to put the id3 tag scanner in a separate process. See here for more informations.
My best advice would be to create a subclass QThread. Pass this subclass a pointer to the directories and give it a pointer to a valid (non-null) view that you want to update in the following way:
header.h
class SearchAndUpdate : public QThread
{
Q_OBJECT
public:
SearchAndUpdate(QStringList *files, QWidget *widget);
//The QWidget can be replaced with a Layout or a MainWindow or whatever portion
//of your GUI that is updated by the thread. It's not a real awesome move to
//update your GUI from a background thread, so connect to the QThread::finished()
//signal to perform your updates. I just put it in because it can be done.
~SearchAndUpdate();
QMutex mutex;
QStringList *f;
QWidget *w;
bool running;
private:
virtual void run();
};
Then in your implementation for that thread do this:
thread.cpp
SearchAndUpdate(QStringList *files, QWidget *widget){
this->f=files;
this->w=widget;
}
void SearchAndUpdate::run(){
this->running=true;
mutex.lock();
//here is where you do all the work
//create a massive QStringList iterator
//whatever you need to complete your 4 steps.
//you can even try to update your QWidget *w pointer
//although some window managers will yell at you
mutex.unlock();
this->running=false;
this->deleteLater();
}
Then in your GUI thread maintain the valid pointers QStringList *files and SearchAndUpdate *search, then do something like this:
files = new QStringList();
files->append("path/to/file1");
...
files->append("path/to/fileN");
search = new SearchAndUpdate(files,this->ui->qwidgetToUpdate);
connect(search,SIGNAL(finished()),this,SLOT(threadFinished()));
search->start();
...
void threadFinished(){
//update the GUI here and no one will be mad
}

Qt threading stopped UI from responding

I think I might misunderstood several concepts in Qt's threading,
In my window class, which is derived from QWidget:
class Widget
{
Q_OBJECT
public:
Widget::Widget (QObject *parent = 0) : QObject(parent)
{
moveToThread(&th); // still stuck
connect (&th, SIGNAL(started()), SLOT(doWork()));
th.start();
}
private:
QThread th;
private slots:
void doWork ()
{
// hmm, this stuck the UI
while (1)
{
qDebug() << "Sleeping";
}
};
};
The forever loop stuck the UI, it shouldn't be, since that was called by the QThread.
Can anyone point out what's wrong about this code?
Widget::dowork() is executed on the main thread (on which the GUI runs), that's why it blocks. It doesn't matter that it was called by a QThread.
The correct way to execute code on another thread is to first move a QObject instance to a QThread using QObject::moveToThread(), and then connect the started() signal of the QThread to the slot of the QObject instance that you want executed.
If you want to know more: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
Another issue with your code is that you're trying to move a QWidget-derived object to another thread. This is not allowed. QWidget instances must remain on the main thread. Instead, you should subclass from QObject.
Yet another issue with the code is that you're doing this in the constructor. Moving the object to another thread while it's not fully constructed yet is just asking for trouble.

QObject::moveToThread and executing a member function inside that thread

If an object of type QObject is moved to a thread with QObject::moveToThread, all signals that the object receives are handled inside that thread. However, if a slot is called directly (object->theSlot()) that call will still block. What would be the normal way of executing that call inside the thread and returning control to the calling thread immediately? Hacks with QTimer don't count. Setting up a single purpose connection and deleting it again might count as a solution if all else fails.
You could use QMetaObject::invokeMethod with Qt::ConnectionType set to Qt::QueuedConnection
You can use QFuture<T> QtConcurrent::run ( Function function, ... ) to launch some execution inside a separate thread and then use QFutureWatcher to get the result. You will not need to call movetoThread.
Basically something like :
QFutureWatcher<T>* watch = new QFuture(0);
connect(watch, SIGNAL(finished()), this, SLOT(handleResult()));
QFuture<T> future = QtConcurrent::run( myObj, &QMyObject::theSlot(), args...);
watch.setFuture(future);
....
//slot
private void handleResult(){
if(future->isCancelled())
return;
T mydata = watch->future()->result();
// use your data as you want
}
QtConcurrent::run will schedule the method of this object to be ran in some thread. It is non-blocking. On the other hand, QFuture::result() blocks until there is a result, if the computation is still ongoing. That's why you need the other object to notify when the computation is over using finished(). I cannot think of a better design for your problem in Qt.

QNetworkAccessManager crashes on delete

I have a class 'Downloader' derived from QObject that runs in a worker thread. When the thread is started, the downloader creates a QNetworkAccessManager object on the heap, and starts to request files. I keep track of how many files have been requested and received. Once I've gotten all of the files, I delete the QNetworkAccessManager object and exit the thread. My problem is that deleting the manager object causes a crash no matter when or where I do this. I've even tried manager->deleteLater(). If I don't delete it, my code runs great, but I know there is a memory leak there. Here is a stripped down version of my code.
Creating the downloader and thread, and setting signals up so that starting the thread starts the downloads, and when the downloads are complete, the thread stops:
QThread thread;
Downloader downloader;
downloader.setFiles(files);
downloader.moveToThread(&thread);
downloader.connect(&thread, SIGNAL(started()), SLOT(downloadFiles()));
thread.connect(&downloader, SIGNAL(downloadsFinished()), SLOT(quit()));
thread.start();
Implementation for the downloader:
void Downloader::downloadFiles()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)));
receivedCount = 0;
requestCount = files.count();
for (QStringList::const_iterator pos = files.begin(); pos != files.end(); ++pos)
{
QUrl url(*pos);
manager->get(QNetworkRequest(url));
}
}
void Downloader::finished(QNetworkReply *reply)
{
// *** Get the file data and process it *** //
++receivedCount;
reply->deleteLater();
if (receivedCount == requestCount)
{
// manager->deleteLater();
emit downloadsFinished();
}
}
The commented out line will crash the app. Even deleting the manager in Downloader's destructor, or setting the downloader as the manager's parent will crash the app.
I first tried creating the manager as a regular member variable on the stack, but doing so causes errors of it's own since the manager would be created in the GUI thread and later try to create children on a different thread.
And before anybody says "QNetworkAccessManager is asynchronous. Why use it in a worker thread?" I have my reasons. It shouldn't be THAT unheard of to do something like this.
The only obvious problem is below but I am not sure if you have posted your entire code or not
void Downloader::downloadFiles()
{
QNetworkAccessManager *manager = new QNetworkAccessManager();
You are creating a local QNetworkAccessManager *manager in your method but not keeping a reference to it and then trying to access it within finished() method.
You should assign new QNetworkAccessManager(); a member variable !

Resources