I was for hours trying to reduce this error to a minimal example, but could not succeed.
I have a GUI with a QPushButton importPCDButton. It should open a QFileDialog and import the selected file. I want to use a thread hoping that the dialog vanishes as soon as I send an update signal to my GUI. So I have an ImportPCD worker class derived from QObject implementing a public slot with the name process(). Inside this, I open the QFileDialog, etc:
void ImportPCD::process() {
std::cout << "foo \n";
QString file_abs = QFileDialog::getOpenFileName(
&*(getControl()->getGuiPtr()),
tr("OpenFile"),
"../data/",
tr("Point Cloud File(*pcd);;ASCII - File(*.asc);;All Files(*)"));
int index = file_abs.lastIndexOf("/");
int size = file_abs.size();
int position = size-index-1;
QString file = file_abs.right(position);
index = file.indexOf(".");
file = file.left(index);
getControl()->setTreeID(file.toStdString());
QString abort;
if(file!=abort)
{
this->path = file_abs.toStdString();
cloudRGB = import ();
emit updateUI();
computeNormals (cloudRGB);
emit updateUI();
principalCurvatures = computeCurvature ();
setRGB ();
getControl()->setCloudPtr(getCloudRGB());
}
emit finished();
}
It also implements the slots updateUI() and finished().
I have a public slot importPCDFile() in my GUI:
void PCLViewer::importPCDFile() {
boost::shared_ptr<QThread> thread_ptr (new QThread);
boost::shared_ptr<ImportPCD> importWorker (new ImportPCD(control));
importWorker->moveToThread(&*thread_ptr);
// connect (ui->importPCDButton , SIGNAL(clicked()), &*thread_ptr, SLOT(start()));
connect (&*thread_ptr, SIGNAL(started()), &*importWorker, SLOT(process()));
// connect (ui->importPCDButton , SIGNAL(clicked()), &*importWorker, SLOT(process()));
connect (&*importWorker, SIGNAL(updateUI()), this, SLOT(updateUI()));
connect (&*importWorker, SIGNAL(finished()), this, SLOT(updateUI()));
connect (&*importWorker, SIGNAL(finished()),&*thread_ptr, SLOT(quit()));
// connect (&*importWorker, SIGNAL(finished()),&*thread_ptr, SLOT(quit()));
connect (&*thread_ptr, SIGNAL(finished()), &*thread_ptr, SLOT(deleteLater()));
// connect (&*thread_ptr, SIGNAL(finished()), &*importWorker, SLOT(deleteLater()));
thread_ptr->start();
}
This method is invoked when I press the button and I get the error:
QThread: Destroyed while thread is still running
Related
My code has following structure:
include
-> myserver.h
-> mythread.h
-> mainwindow.h
src
-> myserver.cpp
-> mythread.cpp
-> mainwindow.cpp
main.cpp
MyServer class creates a new thread for each connection. In that thread, I am reading the data from the client and want to send it to mainwindow.cpp. For this, I am thinking of using signal and slots. Since I have not declared MyThread in mainwindow, I am not able to use connect().
mythread.h:
signals:
void newDataRecieved(QVector<double> x,QVector<double> y);
mythread.cpp:
void MyThread::func(){
.
.
.
emit newDataRecieved(x,yC);
}
myserver.cpp:
void MyServer::incomingConnection(qintptr socketDescriptor)
{
// We have a new connection
qDebug() << socketDescriptor << " Connecting...";
MyThread *thread = new MyThread(socketDescriptor, this);
// connect signal/slot
// once a thread is not needed, it will be beleted later
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
mainwindow.h:
public slots:
void newValues(QVector<double> x,QVector<double> y);
main.cpp:
.
.
#include "myserver.h"
int main(int argc, char *argv[])
{
.
.
w.show();
MyServer server;
server.startServer();
return a.exec();
}
Is there any way to solve this?
Create a signal
void newDataRecieved(QVector<double> x,QVector<double> y);
In MyServer class and then connect the signal newDataRecieved form MyThread to the same signal of MyServer. Then in mainwindow connect a slot to the signal form MyServer.
Is there a way trigger a signal from another signal in Qt?
[EDIT]
Something like this:
myserver.h:
signals:
void newDataRecieved(QVector<double> x,QVector<double> y);
myserver.cpp:
void MyServer::incomingConnection(qintptr socketDescriptor)
{
// We have a new connection
qDebug() << socketDescriptor << " Connecting...";
MyThread *thread = new MyThread(socketDescriptor, this);
// connect signal/slot
// once a thread is not needed, it will be beleted later
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(newDataRecieved(QVector<double>, QVector<double>)), this, SIGNAL(newDataRecieved(QVector<double>, QVector<double>)));
thread->start();
}
I have a main class that launches a thread that performs a single action. I am trying to catch when the thread operations finish.
The main class:
// .h
class MainClass : public QObject
{
Q_OBJECT
public:
QThread thread;
// ...
public slots:
void onFinish();
}
// .cpp
void MainClass::startThread()
{
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(worker, SIGNAL(finished()), this, SLOT(onFinish()));
// connect(worker, SIGNAL(finished()), this, SLOT(onFinish()), Qt::DirectConnection);
}
void MainClass::onFinish()
{
std::cout << "Finished!" << std::endl << std::flush;
}
The Worker class for the thread:
// .h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
~Worker();
public slots:
void process();
signals:
void finished();
}
// .cpp
void Worker::process()
{
// ...Do stuff...
emit finished();
}
Executing startThread does not print "Finished!". Why?
I have noticed that if I add Qt::DirectConnection to the line that connects to onFinish() (like in the commented line), the message is printed. But what can I do if I want to execute the onFinish() actions in the thread of the main class?
Edit 1
In addition, it seems that the finished() -> quit() connect is also not working, because if I call thread->isFinished() or thread->isRunning(), after sleeping in the main thread to be sure that the thread task is completed, I obtain false and true, respectively.
Edit 2
Since it may also be relevant, here is the main.cpp:
int _tmain(int argc, _TCHAR* argv[])
{
QCoreApplication a(argc, argv);
std::unique_ptr <MainClass> mc = std::make_unique <MainClass>();
mc->startThread();
mc->thread->wait();
return a.exec();
}
On a first look I would say that the order of connections is important. The deleteLater() slots should always be the last methods.
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), this, SLOT(onFinish()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
Sitenode - QRunnable
You might consider to use QRunnable instead, which is designed for short running tasks/jobs. You can combine them with QObject or QFuture/QFutureWatcher to get notified as soon as they a finished.
Update 1
Your main-event loop never starts and it looks like you want to exit the application when the task finishes. I don't think this is a nice implementation but these modifcations should work for you:
int _tmain(int argc, _TCHAR* argv[])
{
QCoreApplication a(argc, argv);
std::unique_ptr<MainClass> mc = std::make_unique<MainClass>();
mc->startThread();
// do not wait!
// let the main-event-loop handle events -> a.exec()
// and quit() application by signal/slot
return a.exec();
}
void MainClass::startThread()
{
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), this, SLOT(onFinish()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), qApp, SLOT(quit()));
}
void MainWindow::on_pushButton_clicked()
{
QFuture<int> future = QtConcurrent::run(identify); //Thread1
if (future.isFinished())
{
//DoSomething();
}
}
I have this code. I want to run the DoSomething() function after the identify function finished running. Is it possible?
You can pass the QFuture object to a QFutureWatcher and connect its finished() signal to the function or slot DoSomething().
For example:
void MainWindow::on_pushButton_clicked()
{
QFuture<int> future = QtConcurrent::run(identify); //Thread1
QFutureWatcher<int> *watcher = new QFutureWatcher<int>(this);
connect(watcher, SIGNAL(finished()), this, SLOT(doSomething()));
// delete the watcher when finished too
connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
watcher->setFuture(future);
}
void MainWindow::DoSomething() // slot or ordinary function
{
// ...
}
Or you could use a nested event loop to keep the GUI responsive and have everything inside the same function:
void MainWindow::on_pushButton_clicked()
{
QFuture<int> future = QtConcurrent::run(identify); //Thread1
QFutureWatcher<int> watcher;
QEventLoop loop;
// QueuedConnection is necessary in case the signal finished is emitted before the loop starts (if the task is already finished when setFuture is called)
connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()), Qt::QueuedConnection);
watcher.setFuture(future);
loop.exec();
DoSomething();
}
I like this call layout.
auto watcher = new QFutureWatcher<int>(this);
connect(watcher, &QFutureWatcher<int>::finished,
[watcher, this] ()
{
watcher->deleteLater();
auto res = watcher->result();
// ...
});
watcher->setFuture(QtConcurrent::run(identify, param1, param2));
I get every time the message: QObject::moveToThread: Cannot move objects with a parent
mainwindow.cpp:
QTimer *timer_ = new QTimer(this);
Device* device = new Device(this);
QThread* thread = new QThread(this);
device->moveToThread(thread);
connect(timer_, SIGNAL(timeout()), device, SLOT(checkConnection()));
connect(device, SIGNAL(checkCompleted()), this, SLOT(doSomethingWhenItIsDone()));
timer_->start(3000);
Device.cpp:
Device::Device(QObject *parent) :
QObject(parent)
{
}
void Device::checkConnection() {
qDebug() << "checkConnection:" << QThread::currentThreadId();
//do something
emit checkCompleted();
}
this inside Device constructor means that Device has a parent and this parent in your case lives in main GUI thread, so Qt tells you that you can't move to another thread object which has parent. So try to use next:
QTimer *timer_ = new QTimer(this);
Device* device = new Device;//no parent
QThread* thread = new QThread(this);
Also you should start your thread with:
thread->start();
Also you need delete your object because it has no parent and it is your responsibility now. The most common way is to use some signal to indicate that worker already done all needed work. For example:
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
i have something really strange i have this code :
i think i know what is wrong but i dont know how to fix it .
this is what i have :
when i put break point in int test = 0;
it getting there before it gets to httpFinished() slot in the HttpClient , mybe this is the problem ?
in the main.cpp
---------------------------------------------------------------------------------------------------------
#while (i.hasNext())
{
i.next();
ThreadWorker* pThreadWorker = new ThreadWorker();
pThreadWorker->setUrl(sUrl);
QThreadPool::globalInstance()->start(pThreadWorker);
}
QThreadPool::globalInstance()->waitForDone();
---------------------------------------------------------------------------------------------------------
void ThreadWorker::run()
{
startWork();
}
void ThreadWorker::startWork()
{
m_pHttpClient = new HttpClient();
m_pHttpClient->startRequest(m_url);
int test = 0;
}
--------------------------------- HttpClient based on the http example from Qt -----------------------------------
HttpClient::HttpClient()
{
m_networkManager = new QNetworkAccessManager(this);
connect(m_networkManager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
this, SLOT(slotAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
#ifndef QT_NO_OPENSSL
connect(m_networkManager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
#endif
}
void HttpClient::startRequest(QUrl url)
{
m_url.setUrl("http://qt.nokia.com/");
QNetworkRequest request;
request.setUrl(m_url);
reply = m_networkManager->get(request);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply,SIGNAL(finished()),
this, SLOT(httpFinished()));
connect(reply, SIGNAL(readyRead()),
this, SLOT(httpReadyRead()));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(updateDataReadProgress(qint64,qint64)));
}
the httpFinished() function that is under private slots: never triggered , why ?
UPDATED THE QUESTION
Since the HttpClient and QNetworkAccessManager objects are created within the thread, they automatically belongs to that thread (see QObject::moveToThread), and they both needs an event loop running in that thread, for QNAM to do any work at all, and for your QObject derived class to be able to execute the slots.
You could add a call to QThread::exec() in run() to run that event loop (if you were using QThread):
void Thread::run()
{
startWork();
exec();
}
or create and start a QEventLoop whose quit() slot has to be connected somewhere to stop the loop (for example a finished() signal in the class HttpClient that you would emit when the work is done):
void ThreadWorker::run()
{
startWork();
QEventLoop loop;
QObject::connect(m_pHttpClient, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
}
Also, since Qt 4.8, QNetworkAccessManager is multithreaded, so you might not need to use threads yourself.