Wait for buttonPressed() slot to finish before executing buttonReleased() - c++

I have a QPushButton that performs lengthy actions on pressed() and released() signals. How can I make sure that I finished executing all actions of the buttonPressed() slot, before executing the ones of the buttonReleased() slot?
I have tried with QMutex, but the program seems to be stuck in an endless loop when trying to lock upon button release, when the mutex is still locked by the buttonPressed() function:
mymainwindow.h:
#include <QMutex>
// ...
QMutex mutex;
mymainwindow.cpp:
#include <QEventLoop>
#include <QTimer>
// ...
// In the main window constructor:
connect(myButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
connect(myButton, SIGNAL(released()), this, SLOT(buttonReleased()));
// ...
void MyMainWindow::buttonPressed()
{
mutex.lock();
// Here, I do the lengthy stuff, which is simulated by a loop
// that waits some time.
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
mutex.unlock();
}
void MyMainWindow::buttonReleased()
{
mutex.lock();
// ... (some stuff)
mutex.unlock();
}

Generally using mutex is a thread sync mechanism, here you do not need thread sync since you are in the same thread. Otherwise I would suggest using QWaitCondition to wait for a flag/mutex to change (i.e. to signal your condition is now ok to go).
In your case you can just emit a signal once your "buttonPressed" actions are completed (i.e. when your timer ends?). If the end of buttonPressed() function is the when you want to execute your buttonRelease() function then you can just simply use Qt::QueuedConnection's to ensure the correct order of events (I generally don't like direct connections since they act like function calls (or even interrupts - like what I think is happening to you). So the following change might fix this for you in a simple way:
// In the main window constructor:
connect(myButton, SIGNAL(pressed()), this, SLOT(buttonPressed()), Qt::QueuedConnection);
connect(myButton, SIGNAL(released()), this, SLOT(buttonReleased()), Qt::QueuedConnection);
I am not sure if executing your event loop to "simulate" your "long amount of time" will work.... but if you do somthing more like the following to simulate your long execution time:
QElapsedTimer elapsedTime;
elapsedTime.start();
while (elapsedTime.elapsed() < 1000) // millisecs
{
// wait....
}
If this does not work, then just emit a signal at the end of buttonPressed() and set a flag in buttonReleased() such that:
void MyMainWindow::buttonPressed()
{
// actions here
emit buttonPressedDone();
}
void MyMainWindow::buttonReleased()
{
btnReleased = true;
}
void MyMainWindow::buttonPressedCompleted()
{
if (btnReleased )
{
// Do button released actions here
btnReleased = false;
}
// I am assuming that if the flag is not set then you don't want to do anything... but up to you...
}
and connect buttonPressedDone --> buttonPressedCompleted
There are load more options...these are just a few more options for you...

Is it necessary connect to release SLOT of your button? You can just connect to destroyed() SIGNAL of your QEventLoop and call buttonReleased() SLOT.
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
connect(&loop, &QEventLoop::destroyed, this, &MyMainWindow::buttonReleased);
loop.exec();
EDITED BY COMMENT:
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
connect(&loop, &QEventLoop::destroyed, [=] {
connect(myButton, &QPushButton::released, this, &MyMainWindow::buttonReleased);
});
loop.exec();

Related

Properly terminate a QThread

I've have a worker class that do image acquisition in the background.
void acq::run ()
{
while (m_started)
{
blocking_call();
}
emit workFinished();
}
void acq::start ()
{
m_started = true;
run();
}
void acq::stop ()
{
m_started = false;
}
start (); stop () are slots and workFinished is a signal.
So in my UI Class, I launch the worker and I connect the signals to the slots :
m_thread = new QThread;
m_worker = new acq();
m_worker->moveToThread(m_thread);
// When the thread starts, then start the acquisition.
connect(m_thread, SIGNAL (started ()), m_worker, SLOT (start ()));
// When the worker has finished, then close the thread
connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));
m_thread->start();
At this point, I implemented the slot, closeEvent
void UIClass::closeEvent (QCloseEvent *event)
{
m_worker->stop(); // tell the worker to close
m_thread->wait(); // wait until the m_thread.quit() function is called
event->accept(); // quit the window
}
Unfortanely, m_thread->wait() is blocking. Even if the signal quit() is emmited
Thanks
edit:
I added these two connections :
connect(m_worker, SIGNAL(workFinished()), m_worker, SLOT(deleteLater()));
connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
and a Qdebug into acq::~acq()
The message is printed that prove, that stop is called, workFinished is emitted, deleteLater() is emitted.
A normal signal/slot connection between objects on different threads requires that the thread of the receiver object runs an event loop.
Your receiver thread does theoretically run its event loop, but the event loop is busy executing the start() slot because run() never returns.
You either need to unblock the receiver event loop or call the stop slot with a Qt::DirectConnection.
When doing the latter you need to be aware that the slot is now called in the context of the sender thread and you need to protect m_started against concurrent access.
Alternatively to using your own flag you could use QThread::requestInterruption() and QThread::isInterruptionRequested()
Add
QCoreApplication::processEvents();
to your loop and it'll work.
The reason you deadlock is that the call to acq::run() blocks and does not leave time for acq::stop() to be executed on the worker thread.
With the help of Ralph Tandetzky and Kevin Krammer I finally found a solution.
Instead of closing the thread with m_worker->stop();, I use QMetaObject::invokeMethod(m_worker, "stop", Qt::ConnectionType::QueuedConnection); and QCoreApplication::processEvents(); in the worker event loop. The behavior does not change, but I hope it will prevent race condition or other problems.
Instead of using : connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));, I use a custom slot :
connect(m_worker, &Acq::workFinished, [=]
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
});
We use DirectConnection because we are outside the infinite loop, so the event are not processed.
With that, I had a last problem. m_thread->wait is blocking, and I've to read events, otherwise, my custom slot will never be called. So added an event loop to my UI Class QEventLoop m_loop.
Just before m_thread->wait(), I wrote m_loop.exec();
And finally, In my custom slot, I put m_loop.quit()
connect(m_worker, &Acq::workFinished, [=]
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
m_loop.quit();
});
m_loop.exec() process event until quit m_loop.quit() is called. With that method, I don't even need m_thread->wait() because m_loop.quit() is called when workFinished is emitted. I don't need QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection); anymore
Now it works like a charm
EDIT: This solution is very heavy and ugly, Qt (https://www.qtdeveloperdays.com/sites/default/files/David%20Johnson%20qthreads.pdf) sugest to use subclass and requestInteruption in my case.

main thread cannot get signal form worker thread

This is part of the main.
This code create a worker and a workerthread.
The worker is moved to the workerthread.
The worker is then waiting for the signal to ask it to work.
The worker emit a signal with result when job done.
The main supposed to catch that signal and initialize a variable in the main.
main()
{.........
// This is the variable to be changed
variableToGetFromWorker = 0;
qDebug() << "Main thread: " << QThread::currentThreadId();
QThread workerThread;
worker* stupidTom = new stupidTom(number);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob()));
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int)));
workerThread.start();
workerThread.wait();
...........}
// This is a slot at main. Suppose to catch the signal from the worker
void main::jobDone(int result)
{
qDebug() << "Changing variable";
variableToGetFromWorker = result;
}
This is the doJob slot of the worker.
void worker::doJob()
{
qDebug() << "worker::doJob invoked.";
qDebug() << "worker Thread:" << QThread::currentThreadId();
// Doing Job here
emit jobDone(result);
}
It is the qDebug result
Main thread: 0x7ffff7fc6780
worker::doJob invoked.
worker Thread: 0x7fffdab44700
In Debug mode, I find that the program is stop at workerThread.wait()
and never go to main::jobDone(int result). What is the reason?
Little editing on the main code:
QThread workerThread;
worker* stupidTom = new stupidTom(number);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob()));
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int)));
connect(stupidTom, SIGNAL(jobDone(int)), &workerThread, SLOT(quit()));
workerThread.start();
workerThread.wait();
As long as signals supposed to invoke slots. That won't be working on wait() on the main thread that supposed to run the slot or specifically jobDone signal.
Make sure to understand the difference between QThread::exec() and QThread::wait() in your application. Normally in the real app your thread would be looping (running) while the thread that launched it is still looping as well. The loop is implemented in protected QThread::exec() method. We usually don't need to call exec() explicitly but we need to allow the thread to run. You can do that by making main function to use QEventLoop for looping:
int main()
{
//...
workerThread.start();
QEventLoop eventLoop;
// here you will probably want to hook-up QEventLoop::quit() slot
// to eventually quit the process
int returnCode = eventLoop.exec();
//...
return returnCode;
}
And this is also wrong:
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob()));
Instead you should create your own job object and do QObject::moveToThread for it. Here is a nice article about it. So it should rather look like:
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob()));
I likely understand why you attempted to run the thread that way as above. It is similar to many C++ examples. You can also do that in Qt but you also need to realize how exactly you'll be waiting on completion of workerThread. And Qt most popular way to do the interaction between threads is with signals and slots. That is why we should use QEventLoop in main. But of course there is an alternative. For lower level plain C++ you can use mutex and condition variable to accomplish the same. Or that same wait() but then there is no signals involved.
Also watch the debug output, whether or not all the connect statements really connect proper signals to slots. In case if there is no connect it prints the warning.

Starting processes in threads as spawned

I have a problem where I am looking to create a processing class, and I want to feed data into it, then put it into a thread, and tell it to start working. Currently, this is what I have to do that:
ProcessingClass *worker = new ProcessingClass(myData);
connect(this, SIGNAL(startWorking()), worker, SLOT(startWorking()));
connect(worker, SIGNAL(doneWorking(data)), this, SLOT(workerFinished(data)));
QThread *workerThread = new QThread;
worker->moveToThread(workerThread);
workerThread->start();
emit(startWorking());
What this ends up doing is it creates the worker, gives it the data that I want it to process, connects what needs to be connected for everything to work, moves it on over to its thread, and then emits the signal to start working. This more or less does what I want it to, but there is an issue. Namely, I want to be putting this into a loop:
while (reason){
...//gathering data to give to the worker
ProcessingClass *worker = new ProcessingClass(myData);
connect(this, SIGNAL(startWorking()), worker, SLOT(startWorking()));
connect(worker, SIGNAL(doneWorking(data)), this, SLOT(workerFinished(data)));
QThread *workerThread = new QThread;
worker->moveToThread(workerThread);
workerThread->start();
}
emit(startWorking());
This does accomplish what I want it to do, but it does so by sticking everything in memory, waiting until it is all there, and then set off every single thread simultaneously to compete for resources until they are all done. Considering that for my current data amount this is over 1000 different threads, each of which takes (from previous iterations of this program) ~1-2 minutes to process the information, and the last version crashed because it ran out of memory (I think...) I don't particularly like this method much anymore.
What I would like to do is figure out a way to move the resources that I want to the thread, and then set off the thread to do the work immediately. Then I want to be able to pause the loop after some amount of threads are running (so as to not overload the computer again) and then continue this loop and set off the next thread after one of the previous threads is done.
Is there a nicer way to accomplish this?
You should have a fixed number of worker threads, and iterate the loop only when there are threads that are not busy.
If you insist on using a QObject, you can create a QRunnable wrapper to run the worker objects until completion in a thread pool, and to track their progress to issue more work:
class ProcessingRunnable : public ProcessingClass, public QRunnable {
void run() Q_DECL_OVERRIDE {
QEventLoop loop;
moveToThread(QThread::currentThread());
QMetaObject::invokeMethod(this, "startWorking", Qt::QueuedConnection);
loop.exec();
moveToThread(0);
}
public:
explicit ProcessingRunnable(const Data & data) :
ProcessingClass(data) {
setAutoDelete(false);
moveToThread(0); // we will be moved to a worker thread later
}
};
class JobManager : public QObject {
Q_OBJECT
QThreadPool m_pool;
QScopedPointer<ProcessingRunnable> m_worker;
int m_jobs;
public:
Q_SIGNAL void allJobsFinished();
Q_SLOT void runJobs() {
while (true) {
if (m_worker) {
if (m_pool.tryStart(m_worker.data())
m_worker.take();
else
break;
}
}
if (! reason) break;
... // gather data to give to the worker
m_worker.reset(new ProcessingRunnable(myData));
++ m_jobs;
connect(m_worker, &ProcessingRunnable::doneWorking, [this]{
-- m_jobs;
runJobs();
if (! m_jobs) emit allJobsFinished();
});
}
}
explicit JobManager(QObject * parent = 0) : QObject(parent),
m_jobs(0) {
}
}
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
...
JobManager manager;
QObject::connect(&manager, &JobManger::allJobsFinished,
&app, &QCoreApplication::quit, Qt::QueuedConnection);
manager.runJobs();
...
return app.exec();
}
For this kind of an application, it might be simpler to make your ProcessingClass be a simple functor, not a QObject, and use QtConcurrent::Run and QFutureWatcher.

Signal from Main Thread not reaching slot in Second Thread Qt 5

I am writing a program that captures an Image from the Camera every REFRESH_RATE milliseconds to send it to some calculation algorithm. I decided to time the launch of this algorithm using a QThread, but the algorithm is running on the main thread, because I need objects created before in this one.
Anyway, this works well.
The trouble begins when I try to shut the second thread down... Here's the code.
Camera:
class Camera : public QMainWindow
{
Q_OBJECT
public:
Camera(QWidget *parent = 0){
AlgoQThread = new QThread;
myAlgoThreadWorker = new AlgoThreadWorker( (Camera *) this );
myAlgoThreadWorker->moveToThread(AlgoQThread);
//Launch The thread
connect(AlgoQThread, SIGNAL(started()), myAlgoThreadWorker, SLOT(process()));
connect(myAlgoThreadWorker, SIGNAL(finished()), AlgoQThread, SLOT(quit()));
// The line meant to stop the thread at next loop
connect(this, SIGNAL(stopAlgoThread()), myAlgoThreadWorker, SLOT(stopThread()));
connect(myAlgoThreadWorker, SIGNAL(finished()), myAlgoThreadWorker, SLOT(deleteLater()));
connect(AlgoQThread, SIGNAL(finished()), AlgoQThread, SLOT(deleteLater()));
AlgoQThread->start();
}
private slots:
void errorString(QString error);
//This function is triggered by a signal sent by the method called in AlgoThreadWoker::process()
void some_algorithm(){
...
emit stopAlgoThread();
}
signals:
void stopAlgoThread();
private:
QThread * AlgoQThread;
AlgoThreadWorker * myAlgoThreadWorker;
};
algoThreadWorker:
class AlgoThreadWorker : public QObject
{
Q_OBJECT
public:
AlgoThreadWorker(Camera * context){
parentCamera = context;
}
Camera* parentCamera;
public slots:
void process(){
while(1){
QMutexLocker locker(&m_mutex);
if (t_stop) break;
parentCamera->isCapturingImage = true;
//This triggers the some_algorithm() using a signal sent by imageCapture from main Thread
parentCamera->imageCapture->capture();
//Wait REFRESH_RATE millisecondes
Sleep(REFRESH_RATE);
}
//Ends the thread
emit finished();
}
private slots:
void stopThread(){
QMutexLocker locker(&m_mutex);
t_stop = true;
};
signals:
void finished();
void error(QString);
private:
bool t_stop;
QMutex m_mutex;
};
And well, as you may have foresee, it doesn't work. I can launch some_algorithm() with no problems but I can't end the thread. The stopThread() slot isn't even launched, I've tested that already.
Since you are busy waiting in your while loop, the event loop never gets a chance to process the received signals.
qApp->processEvents() gives the control to your event loop in order to process the awaiting jobs.
Note that generally you do not have to call it yourself, Qt does it for you. In your case, it is neccessary because you have an endless loop which prevents Qt from doing its job.
Solution :
void process(){
while(1){
qApp->processEvents();
^^^^^^^^^^^^^^^^^^^^^^
.....
}
//Ends the thread
emit finished();
}
stopThread() is private and thus only accessible from AlgoThreadWorker.
Qt's event loop already provides for safe cross-thread slot call and event delivery. Your mistakes are mostly to do with incorrectly reimplementing what Qt already provides:
Things are already thread-safe. Drop the mutex.
thread->quit() works and will exit from the event loop running in the given thread. In a QThread, the thread will then finish,.
Don't make your code non-portable for no reason (Sleep is Windows-specific). If you wish do things periodically, simply run a timer (QBasicTimer or QTimer).
This answer provides a complete example.

How to tell QThread to wait until work is done ,and then finish?

I have a simple application that uses one worker thread.
This worker thread is started and initializes DownloadManager, which is responsible for downloading files from the net.
In my main application class I have the finished() SIGNAL on the thread that is emitted before the DownloadManager finishes.
My question is how to make the worker thread wait until the DownloadManager finishes its work.
Here is example code :
class Main
{
m_DownloadWorker = new DownloadWorker(this);
QObject::connect(pm_hotosDownloadWorker, SIGNAL(finished()), this, SLOT(DownloadWorkerFinished()));
m_DownloadWorker->Execute();
// do i need to do here something so the thread will wait ?
.....
void Main::DownloadWorkerFinished()
{
Log("DownloadWorkerFinished");
}
};
class DownloadWorker : public QThread
{
void DownloadWorker::Execute()
{
// do i need to do here somthing so the thread will wait ?
start();
}
void DownloadWorker::run()
{
// do i need to do here somthing so the thread will wait ?
DownloadManager* pDownloadManager = new DownloadManager(this);
pDownloadManager->download();
}
};
class DownloadManager: public QObject
{
// downloading stuff using Qt networkmanager
.....
.....
}
In cases when you have a signal that is emitted when an asynchronous operation is completed, you can always use QEventLoop to "turn" the asynchronous operation into synchronous with the current thread. It is still asynchronous, but the thread will "wait" for it to finish.
QNetworkAccessManager nam;
QEventLoop loop;
QNetworkReply *reply = nam.get(request);
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
So basically you put this in you DownloadManager class where you want to do a network request synchronously. exec() will return once the loop's quit slot has been called.
You can use QThread::exec() call to run your thread in the event loop. The thread will run it until you tell your thread to exit by calling QThread::exit(). So some sample code can look like this:
void DownloadWorker::run()
{
DownloadManager* pDownloadManager = new DownloadManager(this);
connect(pDownloadManager, SIGNAL(finished()), SLOT(exit()));
connect(pDownloadManager, SIGNAL(error()), SLOT(exit()));
pDownloadManager->download();
exec();
}
That would guarantee you that your thread won't quit until the "finished()" signal of your DownloadManager is issued.
Note: Here I put an example of how to solve your problem but I don't know your whole app code. That means there is not guarantee this code is thread safe and consistent. You need to take care of the mutexes and all the correct synchronization yourself. Be very careful ! Working with such a "low level" thread API requites good understanding of multithereading.
Hope that helps