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));
Related
What is the corrent way to stop threads in Qt?
Suppose that I have a worker (LicenseChecker class) and I want to do some actions every n seconds in the process member function. I need to do it indefinitely, until someone abort my loop.
_worker = new LicenseChecker;
_thread = new QThread;
_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(newLicensesActivated(QVector<LicenseInfo>)),
this, SLOT(newLicensesActivated(QVector<LicenseInfo>)));
_thread->start();
What can I do to abort it?
The first idea that I came up with was to define the sleep function as the following:
bool LicenseChecker::sleep(int seconds)
{
QTime end_time = QTime::currentTime().addSecs(seconds);
while (QTime::currentTime() < end_time)
{
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
QMutexLocker lock(&_abort_sync);
if (_abort)
{
return false;
}
}
return true;
}
and to check the return code of this function in my infinite loop:
while (true)
{
if (!sleep(5))
{
emit finished();
return;
}
// ...
}
And then on MainWindow's close event I need to do the following:
_worker->stop();
_thread->wait();
where stop member function just sets _abort data member to true, but the application hangs on these calls.
What is the right way to accomplish such task?
Seems that you call stop() from another thread (the main thread) but the worker instance is located in the worker thread. You can overcome this problem by carefully writing something like this to invoke a method from another thread:
void Worker::stop()
{
// make thread safe
if(QThread::currentThread() != this->thread())
{
this->metaObject()->invokeMethod(this, "stop", Qt::QueuedConnection);
return;
}
REAL CODE HERE ...
}
Besides that, i would rather use a timer to fire every n seconds to do the licence check. Something like that (example of an database connection checker):
dbCheckerThread = new QThread(this);
dbCheckerTimer = new QTimer();
dbCheckerTimer->setInterval(CHECKDBCONNECTIONINTERVALL);
dbCheckerTimer->moveToThread(dbCheckerThread);
dbChecker->moveToThread(dbCheckerThread);
connect(dbCheckerTimer, &QTimer::timeout, dbChecker, &DbConnectionChecker::checkConnection);
connect(dbCheckerThread, &QThread::started, dbCheckerTimer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
dbCheckerThread->start();
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
I want to make a condition in code to wait until all threads are finished in the main thread final slot, following is the test code ..
testClass::testClass()
{
m_count = 0;
m_flag = false;
for( int i = 0; i < 3; i++)
{
QThread *thread = new QThread();
WorkerThread *worker = new WorkerThread();
connect(thread, SIGNAL(started()), worker, SLOT(startThread()));
connect(worker, SIGNAL(workerFinished()), this, SLOT(threadFinished()));
connect(worker, SIGNAL(workerFinished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
m_workerList.append(worker);
}
}
void testClass::threadFinished()
{
// wait untill all thread are finished, how to achive this ?
if(!m_flag)
{
// print << m_flag;
m_flag = true;
}
}
void WorkerThread::startThread()
{
emit workerFinished();
}
here testClass is in main thread and I want the application to wait in threadFinished slot until all threads I started in testClass constructor to finish, could anyone suggest best way to do this ?
I am using Qt 5.4.0 in Windows 7.
If using boost in addition to Qt is an option, you can use a thread group and call join_all, which waits until all threads in the group are done.
Also, QThreadPool provides the waitForDone() function ("Waits for each thread to exit and removes all threads from the thread pool."), however you might have to restructure your worker objects slightly to comply to the QRunnable interface.
A more basic solution would be to set a QVector or QMap member variable with one entry for each thread and set them to true when the respective thread finishes. Continue program execution in your slot only when all threads have reached "finished = true" state in your member variable.
I'm trying to correct a large program for memory leaks and threads that are not stopped. I know I have some, but I'm not sure about how to properly identify and kill them, so I started playing with some canonical examples, and I'm already having those.
First I tried the simplest thing:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
return a.exec();
}
That gives me one (1) running thread in the Task Manager.
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne *w = new WorkerOne();
QTimer::singleShot(3456, w, SLOT(stop()));
return a.exec();
}
This one gives me 1 before starting the worker, then 2 until the thread actually starts (process is called), then 3 until the singleShot signal is captured and the worker deleted and then 2 again. So I'm having something loose there.
And this is the code for WorkerOne:
WorkerOne::WorkerOne(QObject *parent)
: QObject(parent)
, m_stop(false) {
QThread* thread = new QThread;
this->moveToThread(thread);
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(this, SIGNAL(finished()), thread, SLOT(quit()));
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
WorkerOne::~WorkerOne() {}
void WorkerOne::process() {
while(!m_stop) {
QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); loop.exec();
}
emit finished();
}
void WorkerOne::stop() {
m_stop = true;
}
void WorkerOne::errorString(QString err) { }
The platform is Qt 5.2.1 with mingw48_32 compiler.
I think I am following the steps in threading howto from Maya Posch's blog, but maybe I am missing something.
Your implementation of the worker object is literally upside down. It's QThread's job to spin the event loop. Your worker object should simply be driven by slot calls and incoming events. A processing busy loop idiom uses a zero-length timer to stay active while allowing the event loop to receive events and quit, with no need for extra flags.
Here's how to do it:
class WorkerOne : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void processChunk() {
...
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) processChunk();
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() { m_timer.start(0, this); }
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne worker;
QThread thread;
thread.start();
worker.start();
worker.moveToThread(&thread);
a.connect(&thread, SIGNAL(finished()), SLOT(quit()));
QTimer::singleShot(3456, &thread, SLOT(quit()));
return a.exec();
}
When the timer times out, the thread's event loop quits, the thread finishes, the application's event loop is quit, and, finally, the thread and the worker get destroyed.
A zero-length timer is not really a timer, just an idiom that means: invoke me as soon as the event loop is entered and there's nothing else to do. Doing the below would be a premature pessimization as there's be a memory allocation per each round through the event loop - not using the timer would be worse!
class WorkerOne : public QObject {
Q_OBJECT
Q_INVOKABLE void processChunk() {
...
// A lame attempt to call ourselves again from the event loop.
// It works, but has lot more overhead than a zero-length timer!
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() {
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
};
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.