How to cancel threads using QThreadPool - multithreading

I can't share code but theres a sort of example below. Here's my problem. Imagine I have a controller class that has an instance of QThreadPool. This class keeps a list of worker objects. When I start a runnable, I create a worker and give it to the runnable. The runnable operates each worker on the different threads. When the runnable is done, it fires a signal back to the controller object. The controller object then reads the results from the worker and deletes the worker. The controller keeps a list of all workers so that it can set the cancel flag on the worker, so that the thread can exit early if necessary.
The problem is that the QThreadPool will wait for all threads to finish when it's destroyed, which will be in the controller destructor. Since signals are queued when fired from the threads, then potentially canceling the workers in the controller destructor will queue the signals to be delivered to the controller. But since the controller will be in the context of the destructor, those signals won't hit the controller slots, and therefore the worker objects won't get destroyed.
Maybe I'm not dealing with the thread pool the way it should be. If I destroy the worker objects in the runnable, then there is potential for the worker to be destroyed before the another thread tries to cancel a worker. Can anyone recommend a good way of creating a cancelable thread pool?
class Controller : public QObject {
Q_OBJECT
public:
virtual ~Controller();
QThreadPool pool;
void startTask();
Q_SLOT void onWorkerDone(Worker * worker);
QList<Worker*> workers;
void cancelAll();
}
void Controller::startTask() {
Worker * worker = new Worker();
connect(pool, SIGNAL(done(Worker *)), this, SLOT(onWorkerDone(Worker *));
workers << worker;
pool.start(new Runnable(worker);
}
void Controller::onWorkerDone(Worker * worker) {
if ( worker ) {
// read worker...
delete worker;
}
}
Controller::~Controller() {
cancelAll();
// Destructor now kills pool object.
// The pool will wait until all threads complete.
// If there are any workers still running on the
// other threads, their done() signals will be
// queued to this instance, and since we're in
// the dtor, they won't make it to the slot,
// and worker won't get deleted.
}
void Controller::cancelAll() {
// loop the list and call cancel.
}

First mistake. You should not create a QThreadPool. This is application whide object so you should use QThreadPool::globalInstance()
If you want to cancel job you have to provide some functionality in Worker class to do so. You need some loop in Worker::run() method which will do your job and pool for value which should change tread safely when loop should finish.

The simple solution is to subclass QThreadPool and add an aboutToWait signal to that class. The signal would need to be emitted in the destructor. You can then hook up the signal to the controller's cancelAll() slot.
For this to work, the pool must be declared after the workers list!
Suppose you destroy the controller (this). The following happens:
Body of this.~Controller executes.
At the end, the object is still an instance of Controller. Now it has to be torn down into an instance of the base class. The members will be destructed in reverse of the order of declaration.
threadPool is destroyed first. threadPool.~MyThreadPool emits aboutToWait.
this.cancelAll runs, since it's directly connected. The call originates in the moc-generated implementation of the signal method. It lets the workers know that they should stop.
Remainder of threadPool.~MyThreadPool runs, and members (if any) are destructed in reverse order of declaration. this is now an instance of QThreadPool.
threadPool.~QThreadPool runs and waits for the workers to stop. As each worker stops, the controller.onWorkerDone is invoked, since it's directly connected to relevant thread pool's signals. Eventually, threadPool.~QObject runs the pool is fully destructed.
workers.~QList runs.
this.~QObject runs.
The controller is fully destructed.

Related

Deleting Qthread on the middle of running

I created a thread with class A and after deleted class A, the thread is not deleted. It continues running.
I explicitly called the thread destructor, quit and exit function but still, the thread did not stop running.
Is there any thing like KILL function to stop the thread execution
void A::init()
{
WorkerThread *Thread = new WorkerThread(this);
}
void B::slotClose()
{
A *obj = getObj();
if(obj)
{
m_pScene->removeItem(obj);
obj->deleteLater(); // this calls thread distructor also but thread execution is not stopping
}
}
From the docs:
Note that deleting a QThread object will not stop the execution of the thread it manages. Deleting a running QThread (i.e. isFinished() returns false) will result in a program crash. Wait for the finished() signal before deleting the QThread.
You should never delete a running QThread object.
So I think it would be the best for you to write some termination/quitting logic in your WorkerThread, expose some slot for example quit and connect signal with this quit slot.
If you just want to terminate the thread no matter what, just connect destroyed SIGNAL to terminate SLOT (http://doc.qt.io/qt-5/qthread.html#terminate)
So assuming your A class derives from QObject, what would you do inside this class is:
connect(this, SIGNAL(destroyed()), Thread, terminate());
If you have your own slot quit exposed, so you make sure you properly stop all that's executing in your loop just instead terminate() use quit().
connect(this, SIGNAL(destroyed()), Thread, quit());
Here's an example of implementing such a logic: http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
Or just put quit = true in your ThreadWorker destructor.
It should be straightforward. Good luck!
Also some official documentation with examples (imo doing it right):
https://wiki.qt.io/QThreads_general_usage
https://doc.qt.io/archives/qt-5.8/qtnetwork-blockingfortuneclient-example.html
https://doc.qt.io/archives/qt-5.8/qtcore-threads-mandelbrot-example.html

Why is there no Qt connection mode to automatically select between Qt::DirectConnection and Qt::BlockingQueuedConnection?

Here is how Qt signal/slot connection works:
Direct Connection The slot is invoked immediately, when the signal is emitted. The slot is executed in the emitter's thread, which is not necessarily the receiver's thread.
Queued Connection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
Blocking Queued Connection The slot is invoked as for the Queued Connection, except the current thread blocks until the slot returns.
Note: Using this type to connect objects in the same thread will cause deadlock.
And there's an extra one which is actually the default: Auto Connection If the signal is emitted in the thread which the receiving object has affinity then the behavior is the same as the Direct Connection. Otherwise, the behavior is the same as the Queued Connection."
The default works pretty well as expected in most cases:
If within a worker thread, queued execution through a queued connection
If within the object thread, execution is made right away
However, when a signal is emited from a thread, you have two options to handle it: "Queued" or "Blocking Queued" Connection.
Why is there no mode that would behave like that:
If within a worker thread, blocking queued execution
If within the object thread, execution is made right away
Because, as the documentation mentions, using a Blocking Queued Connection in the same thread will cause deadlock....so it's a real pain to handle, I often had to create and manage two signals and connections in my code to handle that:
class A
{
Q_OBJECT
public:
A()
{
connect( this, SIGNAL(changedFromThread()), this, SLOT(update()), Qt::BlockingQueuedConnection );
connect( this, SIGNAL(changedNotFromThread()), this, SLOT(update()) );
}
void notifySomethingChanged()
{
if ( QObject().thread() != thread() )
emit changedFromThread(); // would dead-lock if in same thread
else
emit changedNotFromThread();
}
public slots:
void update()
{
// Do some changes to A that cannot be done from a worker thread
}
signals:
void changedFromThread();
void changedNotFromThread();
};
If such a mode (let's call it Qt::AutoBlockingConnection was available), I could have written:
class A
{
Q_OBJECT
public:
A()
{
connect( this, SIGNAL(changedFromThread()), this, SLOT(update()), Qt::AutoBlockingConnection );
}
void notifySomethingChanged()
{
emit changedFromThread(); // would dead-lock if in same thread
}
public slots:
void update()
{
// Do some changes to A that cannot be done from a worker thread
}
signals:
void changedFromThread();
};
Is there any good reason why a thread-friendly connection was only provided to swap between Qt::DirectConnection and Qt::QueuedConnection but none to swap between Qt::DirectConnection and Qt::BlockingQueuedConnection?
I would guess that the Qt dev team do not want you to specify the connection type at all.
I can understand this design, in a sense that intentional blocking should almost always be avoided, even more so if you are blocking the UI Thread.
If you wish to synchronize 2 QObject living in different threads, use signals and slots in both of them, and connect them accordingly.
However, if you are in a Master-Slave scenario (typically QMainWindow owning a QObject with QObject::moveToThread(new QThread)), you can :
Listen to signals from the QObject into your QMainWindow
Call QObject slots using QMetaObject::invokeMethod into
QMainWindow, so the method calls are processed asynchronously by
the QObject thread.

How to unblock a QThread running a pcsc call?

I have a Qt application that connects to a card reader using various pcsc implementations under GNU/Linux, MacOS, and Windows. All communication with the card runs in a worker thread.
In one scenario, the user starts an operation requiring communication with the card via a card reader. The card reader has a keyboard and during the authentication procedure the user must enter their PIN on the reader's keyboard.
This operation is implemented by a call to SCardControl() (see e.g. the Microsoft documentation). As long as the user is working with the reader, the call to SCardControl() does not terminate and the worker thread is blocked by it.
At this point, the user might decide to close the application while the operation is still pending. Closing the application at this point causes the application to crash (on Linux with signal SIGABRT) because:
The worker thread is blocked waiting for SCardControl() to return.
The main thread cannot stop the blocked thread: neither quit() nor terminate() cause the thread to finish.
When the application is exited, the QThread object for the worker thread is destroyed and, since the thread is still running state, it throws a signal to indicate an error.
I have tried several solutions.
Subclass QThread and create a worker thread which calls setTerminationEnabled(true); to allow termination through QThread::terminate(). This does not work on MacOS: when QThread is destroyed, the thread is still in a running state and the signal SIGABRT is emitted.
Handle signal SIGABRT on shutdown and ignore it. This did not seem to be a good idea but I wanted to try it out before discarding it. After ignoring signal SIGABRT, a signal SIGSEGV is received and the application crashes. I had adapted the approach described here.
Try to unblock the thread by sending a command to the card reader from the main thread. I tried SCardCancel(), SCardDisconnect() and SCardReleaseContext() but none of these commands has any effect on the blocked thread.
I find it quite strange that it is not possible to cleanly shutdown an application when a thread is blocked on some function call, but all the solutions I have tried have not worked and I have run out of ideas. Did I overlook something? Does anybody have any useful hint?
EDIT
I looked into the Qt source code for QThread and found out that on Unix-like platforms QThread::terminate() uses pthread_cancel() internally. But apparently pthread_cancel() does not work / does nothing on Darwin, see e.g. here and here.
So, maybe I will really have to go with the option of showing a dialog to the user asking to remove the card from the reader.
Cleanly shutting down a thread is not possible from outside if it is blocked in a call. You can, however, prevent user from quitting the application before the operation has completed.
void MainWindow::closeEvent(QCloseEvent *closeEvent) {
if (workerBlocked) closeEvent->ignore();
}
In addition, you can show a dialog telling the user the operation has to be completed first.
Also, if possible, you can let the window close but keep the application alive until the operation is complete by setting qApp->setQuitOnLastWindowClosed(false);
The problem boils down to the fact that a QThread object isn't destructible while the associated thread is running. Usually, it would a print statement like this to the debug output:
QThread: Destroyed while thread is still running
Don't agonize over trying to get SCardControl to return so that the worker thread can be quit safely (since it doesn't return as long as the user is interacting with the reader). Instead, You can follow this answer to destruct the QThread object in a safe manner with a minimum amount of changes to your current implementation.
Here is an example that shows what I mean:
#include <QtWidgets>
//a thread that can be destroyed at any time
//see http://stackoverflow.com/a/25230470
class SafeThread : public QThread{
using QThread::run;
public:
explicit SafeThread(QObject* parent= nullptr):QThread(parent){}
~SafeThread(){ quit(); wait(); }
};
//worker QObject class
class Worker : public QObject {
Q_OBJECT
public:
explicit Worker(QObject* parent = nullptr):QObject(parent){}
~Worker(){}
Q_SLOT void doBlockingWork() {
emit started();
//the sleep call blocks the worker thread for 10 seconds!
//consider it a mock call to the SCardControl function
QThread::sleep(10);
emit finished();
}
Q_SIGNAL void started();
Q_SIGNAL void finished();
};
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
//setup worker thread and QObject
Worker worker;
SafeThread thread;
worker.moveToThread(&thread);
thread.start();
//setup GUI components
QWidget w;
QVBoxLayout layout(&w);
QPushButton button("start working");
QLabel status("idle");
layout.addWidget(&button);
layout.addWidget(&status);
//connect signals/slots
QObject::connect(&worker, &Worker::started, &status,
[&status]{ status.setText("working. . .");} );
QObject::connect(&worker, &Worker::finished, &status,
[&status]{ status.setText("idle");} );
QObject::connect(&button, &QPushButton::clicked, &worker, &Worker::doBlockingWork);
w.show();
return a.exec();
}
#include "main.moc"
Notice that the SafeThread's destructor makes sure to wait() until the associated thread has finished execution. And only afterwards, the main thread can proceed to call QThread's destructor.

QT - Show Widget without blocking his GUI

I want to show a widget for displaying an animated loading gif while another function (pthread) computes a task.
I have tried to subclass my widget with a QThread class, and implemented the method run() where I call the method show(). However, my widget GUI froze.
How can I launch a widget where the GUI is processed separately?
You can't have widgets running on anything except the main thread.
Also, unless you're wanting to change how Qt handles threads, you should not be inheriting from QThread.
Instead, create a worker object that inherits from QObject and move that to the new thread. You can read how to really use QThread here.
Your worker object can then be moved to another thread, do its computation and communicate to the Gui widgets, on the main thread, via signals and slots.
For example, here's a brief outline of a worker class: -
class Worker : public QObject
{
Q_OBJECT
signals:
void finished();
void displayWidget();
private slots:
void run();
}
QThread pThread = new QThread;
Worker pObject = new Worker;
// move the pObject to the thread
pObject->moveToThread(pThread);
You can then control the thread with signals and slots.
// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));
// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));
And start the thread: -
pThread->start();
Used this way, it also enables multiple objects to be moved to a single new thread, rather than creating a new thread per object instance.
So now, for example, if you wanted to display a widget at some point during the processing in the worker object, you'd emit its displayWidget() signal, having previously connected it to the Widget's show() slot.
QWidget* pWidget = new QWidget(parent); // assumes parent is initialized
// using Qt 5 connect call
connect(pWorker, &Worker::displayWidget, pWidget, &Widget::show);
You can't use QWidget (nor any derived classes) directly from threads other than the GUI thread. All you can do directly is to use a QImage owned by the worker thread and paint on it directly from that thread. Here, directly means that you are simply calling methods of objects.
What you need is a way to execute show() not directly in the invoking thread, but indirectly within the GUI thread's context. This is quite simple since QWidget::show() is a slot. Thus, from your computation thread, simply do:
QMetaObject::invokeMethod(widget, "show");
That's all. The implementation of invokeMethod will determine that widget lives in a different thread, and will automatically choose the QueuedConnection method of call delivery. Internally, it will post a QMetaCallEvent to widget. The widget's QObject::event method will act on the event and place the call to the show method. This will happen in the GUI thread.
You can use the same approach to set QProgressBar, for example:
int value = ...;
QMetaObject::invokeMethod(progressBar, "setValue", Q_ARG(int, value));

Qt: How do I catch signals from multple threads in a slot where all signals are queued

I have a condition where I have unknown amount of 3rd party threads calling a callback in my application. That callback emits a signal in the context of the threads that called it. Always the same signal, but 10 different threads can emit it at any given moment.
I'd like to queue all of those singlas and process them with the appropriate slot in the context of a single QThread I own.
How do I do that? The following code does not work. Although I see it signals being emitted, from different threads, my "On..." is never called.
QObject::connect(this,SIGNAL(ProcessQueuedOutEvent(int)),
this,
SLOT(OnProcessQueuedOutEvent(int)),
Qt::QueuedConnection);
Does your QThread run the event loop? It has to do it to receive signals:
Queued Connection The slot is invoked when control returns to the
event loop of the receiver's thread. The slot is executed in the
receiver's thread.
Basically queued connection works the following way:
The originator issues a signal.
Qt creates an event and posts it into the receiver event queue.
The receiver goes through its event queue, picks up the events and dispatches the signals into the connected slots.
Hence if you do not run the event queue, the signals are posted but your thread will never receive them.
So basically your thread should do some initialization in run() but then call exec() and pass it to Qt.
If your thread also needs to run some periodic operations besides checking for signals, you can do that by using QTimer::singleShot timers posting signals to the same thread.
See http://qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads
PS. If you pass the pointers via queued connections, the pointer must be valid until the signal is processed, which may be after your function which posted the signal existed. A common error is to post signals with strings as a parameters which are stored in a local char[] buffer. At the moment the buffer is accessed the original function is finished, and the string is already gone. Those errors depend on thread scheduling and therefore hard to debug. If you pass the pointers via queued connection, they must be heap-allocated and the callee must be responsible to free them.
If I understand your problem correctly, you have a callback function executed by many threads. This callback function should emit a signal connected to a slot in a object which is in another thread.
What I suggest is to create a threaded receiver object, using the pattern (moveToThread). Then using the postEvent method to a private implementation method. The call is thread safe (the parameter is copied).
So your callbacks can directly and safely call:
OnProcessQueuedOutEvent
which posts an event to the QThread event loop.
Receiver.h
class Receiver : public QObject
{
Q_OBJECT
public:
explicit Receiver( QObject* parent = 0 );
virtual ~Receiver();
public slots:
void OnProcessQueuedOutEvent( int val );
private slots:
void OnProcessQueuedOutEventImpl( int val );
private:
QThread m_thread;
};
Receiver.cpp
Receiver::Receiver( QObject* parent )
: QObject(parent)
{
moveToThread(&m_thread);
m_thread.start();
}
Receiver::~Receiver()
{
// Gracefull thread termination (queued in exec loop)
if( m_thread.isRunning() ) {
m_thread.quit();
m_thread.wait();
}
}
void OnProcessQueuedOutEvent( int val )
{
QMetaObject::invokeMethod(this, "OnProcessQueuedOutEventImpl", Q_ARG(int,val));
}
void OnProcessQueuedOutEventImpl( int val )
{
// do stuff here
}

Resources