Proper way to run managable background thread with QThread - c++

I need to run few background threads which must be managable in a way that I can safely stop it anytime. Threads should do some repetable task.
I read documentation and the best way which I can find is to subclass QThread and reimplement run() method:
class BackgroundThread: public QThread
{
Q_OBJECT
virtual void run() Q_DECL_OVERRIDE
{
while (true)
{
// do some routine task
// sleep ...
}
}
};
I like this because I can run code in separate thread and I don't need to do unconvient Qt magic with moveToThread and connecting up to 10 signals/slots to properly manage thread resources.
The problem is that I can't find a way to safely stop the thread. I don't want to terminate it in a random place of execution, I would want it to stop when next iteration ends. The only way to achive it which I see now is to add some atomic flag to thread class and set it from main thread when I need to stop it, but I really don't like this solution.
What is the best way to implement managable background thread using Qt5?

You don't need any magic and "10 signals/slots". Just create your worker:
class Worker: public QObject
{
...
public slots:
void routineTask();
}
Somewhere in your code:
QThread bckgThread;
bckgThread.start();
Worker worker;
worker.moveToThread(&bckgThread);
Connect some signal to the routineTask slot to call it or use QMetaObject::invokeMethod.
And when you are done with the thread, just call:
bckgThread.quit();
bckgThread.wait();
That's pretty simple pattern. Why go the hard way and subclass QThread?

Related

Invoking a function on a QThread that is already running

I have seen a lot of examples on the internet (and the Qt documentation) where to use QThread, a subclass of the class is made and then a worker object is moved to that thread. Then essentially the QThread::started() signal is connected to some slot of the worker class object to run a certain function.
Now I would like to do the same in my project, the difference being I would like to move my worker class to a thread that is already running and then call some function on that thread. To achieve this I came up with a slight hack like in the code below, where I use the QTimer class to invoke a public slot in my worker class.
QThread myThread;
myThread.setObjectName("myThread");
myThread.start();
Worker worker;
worker.moveToThread(&myThread);
QTimer::singleShot(0, &worker, [&worker](){
worker.doStuff(5);
});
Is there a more idiomatic way to achieve the same thing?
If "doStuff" is a slot then you can use QMetaObject::invokeMethod:
QMetaObject::invokeMethod(&worker, "doStuff", Qt::QueuedConnection, Q_ARG(int, 5));

QT - force an object to process incoming signals

I am wondering how to tell a QObject to process all signals and call the slots associated with them. Here's the concrete problem I am having, for a better description of the question:
My program consists of three Qthreads : Main, Communication and Input.
The communication thread handles communication via the network, the Input thread handles user input, and both have several signal-slot connections to the main thread. Whenever a network event occurs, or whenever the user inputs a commandline command, a signal from the respective thread is called, which then activates the appropriate connected slot in the main thread. The main thread's role is to process these events. My code looks as follows:
QApplication a(argc, argv);
CommObj co; //inherits from QThread
co.start(); //Starts the thread
InputObj io; //inherits from QThread
io.start(); //Starts the thread
MainObj u(&co,&io);
return a.exec();
Now, what I want to achieve is for the main thread to not reach the last line.
My intentions are to call a method run() within the constructor of MainObj which is going to do something along the lines of this:
void run ()
{
forever
{
//process all signals..
}
}
However, I do not know how to implement the process all signals part. Any advice on how this could be done (including workarounds) would be very welcome.
This is completely unnecessary. a.exec() runs an event loop that will receive and process the events sent by other threads.
When a slot is invoked due to a signal being emitted in a different thread, Qt is posting a QMetaCallEvent to the receiver object. The QObject::event method is able to re-synthesize the slot call based on the data in the event.
Thus, you need to do nothing. a.exec() does what you want. Feel free to invoke it from MainObj's constructor, as qApp->exec() or as QEventLoop loop; loop.exec(), but that's rather bad design.
The real questions are:
Why do you need MainObj's constructor to spin an event loop?
What sort of "user input" are you processing in the io? You can't access any GUI objects from that thread.
Why are you deriving from QThread if you're using Qt's networking? You definitely don't want to do that - it won't work unless you spin an event loop, so you might as well just use a QThread without changes. Well, to be safe, you need just to make the thread destructible, so:
class Thread {
using QThread::run; // make it final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { requestInterruption(); quit(); wait(); }
};
Anyway, by not using standard QThread that spins an event loop, the communication will be one way. Nothing in such threads will be able to react to signals from other threads.
You need to rearchitect as follows:
Use the Thread class as above. It's safe to be destructed at any time.
Have worker objects that run asynchronously using signals/slots/timers.
Move constructed workers to their threads.
What you need is the processEvents function. For example, if you don't want the user to be able to interact with widgets, but you want the graphics to update, use
processEvents(QEventLoop::ExcludeUserInputEvents);
See the documentation for details.

Is this the correct way to use a QThread?

I am looking at some github projects, where one of them did the UDPlink in the following way,
first it subclass QThread to create a class UDPLink:public QThread
and its constructor and deconstructor is like:
UDPLink::UDPLink(UDPConfiguration* config)
: _socket(NULL)
, _connectState(false)
{
Q_ASSERT(config != NULL);
_config = config;
_config->setLink(this);
// We're doing it wrong - because the Qt folks got the API wrong:
// http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
moveToThread(this);
// Set unique ID and add link to the list of links
_id = getNextLinkId();
qDebug() << "UDP Created " << _config->name();
}
UDPLink::~UDPLink()
{
// Disconnect link from configuration
_config->setLink(NULL);
_disconnect();
// Tell the thread to exit
quit();
// Wait for it to exit
wait();
this->deleteLater();
}
Though the code did compile and work, but I wonder whether this way of using a QThread would be correct?
The Qt docs for QThread describe the two ways threading can be done with QThread. Sub-classing QThread was the only way to use QThread initially. To use QThread in this manner, override the run method, which is the QThread method that runs on a new thread. QThread should be thought of as a thread manager, not an object that runs on a separate thread itself. From the docs:
It is important to remember that a QThread instance lives in the old
thread that instantiated it, not in the new thread that calls run().
This means that all of QThread's queued slots will execute in the old
thread. Thus, a developer who wishes to invoke slots in the new thread
must use the worker-object approach; new slots should not be
implemented directly into a subclassed QThread.
When subclassing QThread, keep in mind that the constructor executes
in the old thread while run() executes in the new thread. If a member
variable is accessed from both functions, then the variable is
accessed from two different threads. Check that it is safe to do so.
QThread documentation page
It's because QThread is a thread manager class that a solution for moving objects to threads was created. The comment in the code you provided makes a statement about this change, since that article states that moveToThread(this) isn't a good practice.
Creating an object and moving it to a thread and sub-classing QThread are both valid approaches to threading with Qt, as the documentation now states clearly. There is a benefit to using the worker-object approach, if you desire to use signal/slot connections across thread boundaries: a worker object will have its slots available on the thread it is moved to.
As Qt developer recommended, Code you mentioned is not correct way to use QThread.
Recommended way is suggested here.
Sample code from Post.
Producer producer;
Consumer consumer;
producer.connect(&consumer, SIGNAL(consumed()), SLOT(produce()));
consumer.connect(&producer, SIGNAL(produced(QByteArray *)), SLOT(consume(QByteArray *)));
// they both get their own thread
QThread producerThread;
producer.moveToThread(&producerThread);
QThread consumerThread;
consumer.moveToThread(&consumerThread);
// go!
producerThread.start();
consumerThread.start();

Knowing when a QThread's event loop has started from another thread

in my program, I am subclassing QThread, and I implemented the virtual method run() like so:
void ManagerThread::run() {
// do a bunch of stuff,
// create some objects that should be handled by this thread
// connect a few signals/slots on the objects using QueuedConnection
this->exec(); // start event loop
}
Now, in another thread (let's call it MainThread), I start the ManagerThread and wait for its started() signal, after which I proceed to use the signals and slots that should be handled by ManagerThread. However, the started() signal is essentially emmitted right before run() is called, so depending on thread scheduling I lose some signals from MainThread, because the event loop hasn't started yet!
(EDIT: turns out that's not the problem, it's just the signals are not connected in time, but for the same reason)
I could emit a signal right before calling exec(), but that's also asking for trouble.
Is there any definitive/simple way of knowing that the event loop has started?
Thanks!
EDIT2:(SOLUTION)
Alright, so it turns out the problem isn't exactly what I phrased. The fact that the event loop hasn't started isn't the problem, since signals should get queued up until it does start. The problem is, some of the signals would not get connected in time to be called- since the started() signal is emitted before run() is called.
The solution is to emit another custom signal after all the connections and right before exec. That way all signals/slots are ensured to be connected.
This is the solution to my problem, but not really an answer to the thread title. I have accepted the answer that does answer the title.
I have left all my code below for those curious, with the solution being, to wait for another signal in the instance() method.
CODE:
Many of you are saying that I cannot lose signals, so here is my whole class implementation. I will simplify it to just the bare necessities.
Here is the interface to ManagerThread:
// singleton class
class ManagerThread: public QThread {
Q_OBJECT
// trivial private constructor/destructor
public:
static ManagerThread* instance();
// called from another thread
public:
void doSomething(QString const& text);
// emitted by doSomething,
// connected to JobHandler whose affinity is this thread.
signals:
void requestSomething(QString const& text);
// reimplemented virtual functions of QThread
public:
void run();
private:
static QMutex s_creationMutex;
static ManagerThread* s_instance;
JobHandler* m_handler; // actually handles the requests
};
Some relevant implementations. Creating the singleton instance of the thread:
ManagerThread* ManagerThread::instance() {
QMutexLocker locker(&s_creationMutex);
if (!s_instance) {
// start socket manager thread, and wait for it to finish starting
s_instance = new ManagerThread();
// SignalWaiter essentially does what is outlined here:
// http://stackoverflow.com/questions/3052192/waiting-for-a-signal
SignalWaiter waiter(s_instance, SIGNAL(started()));
s_instance->start(QThread::LowPriority);
qDebug() << "Waiting for ManagerThread to start";
waiter.wait();
qDebug() << "Finished waiting for ManagerThread thread to start.";
}
return s_instance;
}
Reimplementation of run that sets up signals/slots and starts event loop:
void ManagerThread::run() {
// we are now in the ManagerThread thread, so create the handler
m_handler = new JobHandler();
// connect signals/slots
QObject::connect(this,
SIGNAL(requestSomething(QString const&)),
m_handler,
SLOT(handleSomething(QString const&)),
Qt::QueuedConnection);
qDebug() << "Starting Event Loop in ManagerThread";
// SOLUTION: Emit signal here and wait for this one instead of started()
this->exec(); // start event loop
}
Function that delegates the handling to the correct thread. This is where
I emit the signal that is lost:
void ManagerThread::doSomething(QString const& text) {
qDebug() << "ManagerThread attempting to do something";
// if calling from another thread, have to emit signal
if (QThread::currentThread() != this) {
// I put this sleep here to demonstrate the problem
// If it is removed there is a large chance the event loop
// will not start up in time to handle the subsequent signal
QThread::msleep(2000);
emit(requestSomething(text));
} else {
// just call directly if we are already in the correct thread
m_handler->handleSomething(text);
}
}
Finally, here is the code from MainThread that will fail if the event loop doesn't start in time:
ManagerThread::instance()->doSomething("BLAM!");
Assuming that the handler just prints out its text, here is what gets printed out on a successful run:
Waiting for ManagerThread to start
Finished waiting for ManagerThread thread to start.
Starting Event Loop in ManagerThread
ManagerThread attempting to do something
BLAM!
And here is what happens on an unsuccessful run:
Waiting for ManagerThread to start
Finished waiting for ManagerThread thread to start.
ManagerThread attempting to do something
Starting Event Loop in ManagerThread
Clearly the event loop started after the signal was emitted, and BLAM never prints.
There is a race condition here, that requires the knowledge of when the event loop starts,
in order to fix it.
Maybe I'm missing something, and the problem is something different...
Thanks so much if you actually read all that! Phew!
If you setup the connections right, you shouldn't be losing the signals. But if you really want to get a notice on the start of the thread's event loop, you can try QTimer::singleShot() in your run() right before calling exec(). It will be delivered when the event loop starts and only delivered once.
You could look at QSemaphore to signal between threads. Slots and signals are better for ui events and callbacks on the same thread.
Edit: Alternately you could combine QMutex with QWaitCondition if a semaphore is not applicable. More example code to see how you are using the ManagerThread in conjunction with the MainThread would be helpful.
This is a non-issue. Signals between threads are queued (more specifically, you need to set them up to be queued in the connect() call because direct connections between threads aren't safe).
http://doc.qt.io/qt-5/threads-qobject.html#signals-and-slots-across-threads
You could create the signal/slots connections in the constructor of the ManagerThread. In that way, they are certainly connected even before run() is called.

QThread blocking main application

I have a simple form UI that has a slot for a button, starting a thread:
void MainWindow::LoadImage()
{
aThread->run();
}
And the run() method looks like this:
void CameraThread::run()
{
qDebug("Staring Thread");
while(1)
{
qDebug("ping");
QThread::sleep(1);
}
}
When I click the button that calls LoadImage(), the UI becomes unresponsive. I periodically see the "ping" message as the debug output but the UI hangs, does not respond to anything.
Why is my thread not running separately? CameraThread derived as public QThread
I am using gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) with QT libraries and QT Creator from Ubuntu 10.04(x86) repositories.
Short answer: Start your thread by calling aThread->start(); not run(), and make sure you thread's run() method is protected (not public).
Explanation
Calling start() is the correct way to start the thread, as it provides priority scheduling and actually executes the run() method in its own thread context.
It looks like you are going to be loading images in this thread, so I'm going to include some tips before you run into pitfalls many people fall into while using QThread
QThread itself is not a thread. It is just a wrapper around a thread, this brings us to..
signals/slots defined in the CameraThread class will not necessarily run in the thread's context, remember only the run() method and methods called from it are running in a separate thread.
IMHO, subclassing QThread in the majority of cases is not the way to go. You can do it much simpler with the following code, and it will save you many headaches.
class ImageLoader : public QObject {
Q_OBJECT
public slots:
void doWork()
{
// do work
}
};
void MainWindow::MainWindow(/*params*/)
{
ImageLoader loader;
QThread thread;
loader.moveToThread( &thread );
connect( this, SIGNAL( loadImage() ), &loader ,SLOT( doWork() ) );
thread.start();
// other initialization
}
void MainWindow::LoadImage()
{
emit loadImage();
}
Also read the Qt blog regarding this topic.
You have to call thread->start() not run... run is an entry point for thread. Thread is started with start. You call directly run, that's why you block your gui. Check documentation of QThread. virtual void QThread::run() is protected (not without a reason)
I think the problem could be that you are not calling QtCore.QThread._init__(self) in the constructor. I had the same issue. Also I think you should not override the start function, just override the run() function. This solved the same issue that I was having. Even without any sleep() delays, the window should be responsive.