This question already has answers here:
How to execute a functor or a lambda in a given thread in Qt, GCD-style?
(5 answers)
Closed 6 years ago.
I want to call object's slot in its own thread. In other word, to put slot processing into receiver's thread queue.
As I know, it could be done by using
QMetaObject::invokeMethod(objPtr, "someMethod", Qt:: QueuedConnection);
But as for me, this way is unsafe. Because there are no any compile-time checks about existence of method with such name. And in case of some mistype, error will occur only in runtime and only in logs.
Another way is to create dummy signal like
void callObj();
and connect this dummy signal to slot
connect(this, &Obj1::callObj, objPtr, &Obj2::someMethod, Qt:: QueuedConnection);
But this way is looks really bad.
So is there any way to do this?
Thanks in advance for help.
If you have definition of the interface you'll be calling against, you can use a single shot QTimer with 0ms timeout:
QTimer::singleShot(0, obj, &Class::slot);
you can also call it with a lambda
QTimer::singleShot(0, obj, [obj]{ obj->slot(42); } );
This approach requires the target thread to run its own event loop (i.e. QThread::exec()), but since you want to run slots in its thread I assume that's what you want.
It is not unsafe - nothing bad will happen, invokeMethod() will return false if the method doesn't exist. Check the return value to decide further course of action. It won't crash or anything like that.
You can use qobject_cast to make sure your pointer is of the right type, which should be enough to verify if it has the particular method. Other than that, take care not to mistype it and don't use untested code.
Also, consider that there are several other ways to leverage multithreading besides the implicit object thread affinity.
I wouldn't call the dummy signal approach "really bad" - it is just a hack, and hacks go hand in hand with Qt, as huge as the framework might be, it is far from fullproof.
Related
I've faced quite an odd problem with QtConcurrent, mostly because of strange programming desires, maybe it's just an XY-problem, but...
So, there is my code, trying to communicate with the database, a backend code actually (on Qt, yes). It has to work quick and handle some requests, so I need a thread pool. As a well-known fact I suppose the connection establishing itself is a very time-consuming operation, so there is a need in persistent database connections resulting in persistent threads (QSqlDatabase cannot be moved around between the threads). Also it is quite natural to want asynchronous request handling, thus resulting in some need of a simple way to pass them to the persistent threads.
Nothing too complex, lets assume there already exists some boilerplate in a form like...
// That's what I want for now
QFuture<int> res = workers[i]->async(param1, param2);
// OR
// That's what I DO NOT want to get
workers[i]->async(param1, param2, [](QFuture<int> res) { // QFuture to pass exceptions
// callback here
});
That can be done for sure. Why not std::future? Well, it is much easier to use QFutureWatcher and it's signals for notifications about result's readiness. Pure C++ notification solutions are muuuch more complex and callbacks are also someting that has to be dragged through the class hierarchy. Each worker interfaces a thread with DB connections, obviously.
Okay, all of that can be written, but... custom thread pool would mean no QtConcurrent convenience, there seem to be only risky ways to create that QFuture so that it could be returned by the custom worker. QThreadPool is of no use, because it would be a whole big story to create persistent runnables in it. More to say, the boilerplate I've briefly described is gonna be some kind of project's core, used in many places, not something to be easily replaced by a 100 hand-made thread managings.
In short: if I could construst a QFuture for my results, the problem would be solved.
Could anyone point me to a solution or a workaround? Would be grateful for any bright ideas.
UPD:
#VladimirBershov offered a good modern solution which implements observer pattern. After some googling I've found a QPromise library. Of course, constructing a custom QFuture is still hacky and can be only done via undocumented QFutureInterface class, but still some "promise-like" solution makes asynchronous calls neater by far as I can judge.
You can use AsyncFuture library as a custom QFuture creation tool or ideas source:
AsyncFuture - Use QFuture like a Promise object
QFuture is used together with QtConcurrent to represent the result of
an asynchronous computation. It is a powerful component for
multi-thread programming. But its usage is limited to the result of
threads, it doesn't work with the asynchronous signal emitted by
QObject. And it is a bit trouble to setup the listener function via
QFutureWatcher.
AsyncFuture is designed to enhance the function to offer a better way
to use it for asynchronous programming. It provides a Promise object
like interface. This project is inspired by AsynQt and RxCpp.
Features:
Convert a signal from QObject into a QFuture object
Combine multiple futures with different type into a single future object
Use Future like a Promise object
Chainable Callback - Advanced multi-threading programming model
Convert a signal from QObject into a QFuture object:
#include "asyncfuture.h"
using namespace AsyncFuture;
// Convert a signal from QObject into a QFuture object
QFuture<void> future = observe(timer, &QTimer::timeout).future();
/* Listen from the future without using QFutureWatcher<T>*/
observe(future).subscribe([]() {
// onCompleted. It is invoked when the observed future is finished successfully
qDebug() << "onCompleted";
},[]() {
// onCanceled
qDebug() << "onCancel";
});
My idea is to use thread pools with maximum 1 thread available for each.
QThreadPool* persistentThread = new QThreadPool; // no need to write custom thread pool
persistentThread->setMaxThreadCount(1);
persistentThread->setExpiryTimeout(-1);
and then
QFuture<int> future_1 = QtConcurrent::run(persistentThread, func_1);
QFuture<int> future_2 = QtConcurrent::run(persistentThread, func_2);
func_2 will be executed after func_1 in the same one "persistent" thread.
I tried to break down my problem to a small example. The real problem is a more complex communication:
I have a function that triggers a communication and connects and sends messages to a server. If there is an answer, the Client-class emits a signal containing the answer.
void communicate()
{
client.setUpMessage(); // the answer is emitted as a signal and
// and processed in the Slot
// 'reactToAnswer(...)'
client.sendMessage("HelloWorld");
}
void reactToAnswer(QString answer)
{
parser.parseAnswer() // an error could occur
}
What if an error is detected in the slot in which the response is processed? I would like to stop the execution of the function communicate(). This means that the function client.sendMessage("HelloWorld") should no longer be executed.
In my naivety I tried to handle the problem with exceptions:
void communicate()
{
try
{
client.setUpMessage(); // the answer is emitted as a signal and
// and processed in the Slot
// 'reactToAnswer(...)'
client.sendMessage("HelloWorld");
}
catch(myException)
{
// do something
}
void reactToAnswer(QString answer)
{
if( !parser.parseAnswer() )
{
throw myException;
}
}
This does not work, throwing an exception from a slot invoked by a qt-signal is undefined behaviour. The usual way is to reimplement QApplication::notify() resp. QCoreApplication()::notify, but this does not work for me. There is already a QApplication for the GUI and I want the communication class (QObject) to stand alone. All things should be treated within this class.
I hope I explained the problem comprehensibly. I do not want to use exceptions in any case, other ways to stop the communication are also right for me.
Thanks in advance!
I'm not sure that what you are trying to accomplish is a particularly good fit for the signals-and-slots paradigm... perhaps you want to go with just a regular old function call instead? i.e. something like:
void communicate()
{
QString theAnswer; // will be written to by setupMessage() unless error occurs
if (client.setUpMessage(theAnswer))
{
reactToAnswer(theAnswer);
client.sendMessage("HelloWorld");
}
}
The reason that signals-and-slots aren't a good fit is that signals are designed to be connectable to multiple slots at once, and the order in which the slots-methods are called is undefined -- so if a slot-method tries to interfere with the signal-emitting process in the way you describe, the behavior is rather unpredictable (because you don't know how many other connected slot-methods, if any, had already been called as part of the signal-emission, before your particular slot-method hit the brakes). And of course if you ever go to queued/asynchronous signals, then it won't work at all, because the slot will be called in a different context entirely, long after the signal-emitting function has already returned.
That said, if you absolutely must use signals-and-slots for this, you can have your slot emit its own error-has-occurred signal, which can be connected back to a slot in the original signal-emitting class. That slot could then set a boolean (or whatever), and your communicate() method could then check the state of that boolean (right after client.setUpMessage() has returned) to decide whether or not to continue executing or return early.
(I don't recommend that though -- signals-and-slots are there to make your program less complicated, and in this case I think using them instead of a regular function call actually makes your program more complicated, with no corresponding benefit)
This question already has an answer here:
Qt, How to pause QThread immediately
(1 answer)
Closed 5 years ago.
I would like to know how to properly stop a QThread. I havea infinite loop in a thread, and I would like to stop it when I do a specific action :
I have tried :
if (thread->isRunning()){
worker->stop();
thread->terminate();
}
the stop() method set a value to false to go out of my infinite loop.
Furthermore, I don't really understand the difference between quit(), terminate() or wait(). Can someone explain me ?
Thanks.
A proper answer depends on how you actually use QThread and how you've implemented stop().
An intended use case in Qt assumes following model:
You create an object that will do some useful work in response to Signals
You create a `QThread` and move your object to this thread
When you send a signal to your object, it's processed in `QThread` you've created
Now you need to understand some internals of how this is actually implemented. There are several "models" of signals in Qt and in some cases when you "send a signal" you effectively simply call a "slot" function. That's a "direct" slot connection and in this case slot() will be executed in caller thread, one that raised a signal. So in order to communicate with another thread, Qt allows another kind of signals, queued connections. Instead of calling a slot(), caller leaves a message to object that owns this slot. A thread associated with this object will read this message (at some time later) & perform execution of slot() itself.
Now you can understand what's happening when you create and execute QThread. A newly created thread will execute QThread::run() that, by default, will execute QThread::exec() which is nothing, but an infinite loop that looks for messages for objects associated with thread and transfers them to slots of these objects. Calling QThread::quit() posts a termination message to this queue. When QThread::exec() will read it, it will stop further processing of events, exit infinite loop and gently terminate the thread.
Now, as you may guess, in order to receive termination message, two conditions must be met:
You should be running `QThread::exec()`
You should exit from slot that is currently running
The first one is typically violated when people subclass from QThread and override QThread::run with their own code. In most cases this is a wrong usage, but it's still very widely taught and used. In your case it seems that you're violating the second requirement: your code runs infinite loop and therefore QThread::exec() simply doesn't get a control and don't have any chance to check that it needs to exit. Drop that infinite loop of yours to recycle bin, QThread::exec() is already running such loop for you. Think how to re-write your code so it does not running infinite loops, it's always possible. Think about your program in terms of "messages-to-thread" concept. If you're checking something periodically, create a QTimer that will send messages to your object and implement a check in your slot. If you processing some large amount of data, split this data to smaller chunks and write your object so it will process one chunk at a time in response to some message. E.g. if you are processing image line-by-line, make a slot processLine(int line) and send a sequence of signals "0, 1, 2... height-1" to that slot. Note that you will also have to explicitly call QThread::quit() once done processing because event loop is infinite, it doesn't "know" when you processed all the lines of your image. Also consider using QtConcurrent for computationally-intensive tasks instead of QThread.
Now, the QThread::terminate() does stop a thread in a very different manner. It simply asks OS to kill your thread. And OS will simply abruptly stop your thread at arbitrary position in the code. Thread stack memory will be free'd, but any memory this stack pointed to won't. If a thread was owning some resource (such as file or mutex), it won't ever release it. An operation that involve writing data to memory can be stopped in the middle and leave memory block (e.g. object) incompletely filled and in invalid state. As you might guess from this description, you should never, ever call ::terminate() except for very rare cases where keeping running of thread is worse than getting memory & resource leaks.
QThread::wait() is just a convenience function that waits until QThread ceases to execute. It will work both with exit() and terminate().
You can also implement a threading system of your own subclassed from QThread and implement your own thread termination procedure. All you need to exit a thread is, essentially, just to return from QThread::run() when it becomes necessary and you can't use neither exit() nor terminate() for that purpose. Create your own synchronization primitive and use it to signal your code to return. But in most cases it's not a good idea, keep in mind that (unless you work with QEventLoop by yourself), Qt signal and slots won't be working properly in that case.
Related to Qt: Do events get processed in order?
Do Qt::QueuedConnection signals always get invoked in order?
So:
void A::func()
{
emit first_signal();
emit second_signal();
}
If these are both connected by Qt::QueuedConnection to slots will they always be invoked in the order first_signal() then second_signal()?
Given the fact that bug(s) regarding the event prioritization are still being fixed very recently (target version 4.8.0), better don't rely on it. The observation that docs avoid any bold statements most probably means that the devs are simply not so sure.
If the documentation does not state it, you should rather not assume it.
It seem that the only implementation that provide Safe Cross-Thread Signals for both the Signal class and what's being called in the slot is QT. (Maybe I'm wrong?).
But I cannot use QT in the project I'm doing. So how could I provide safe Slots call from a different thread (Using Boost::signals2 for example)? Are mutex inside the slot the only way? I think signals2 protect themself but not what's being done inside the slot.
Thanks
You can combine boost::bind and boost ASIO to create Cross-Thread Calls.
# In Thread 2
boost::asio::io_service service;
boost::asio::io_service::work work (service); // so io service won't stop if there is no work
service.run() # starting work thread
# In Thread 1
service.post (boost::bind (&YourClass::function, &yourClassInstance, parameter1, parameter2))
Thread 2 will go into a loop and will execute your bound function. I think you can also call Boost::Signals2 calls into this loop.
But keep care: If you do cross-thread-signaling, make sure that the destination object still exists when being called. You can garantuee that by dropping all connections in your targets destructor (not in their base class destructor, also see Signals-Trackable Class)
I do not like Boost::Signals2 oo much, because of its very long stack trace and compile times (blog post).
It's not a signals-slots implementation, exactly, but there's a C++ implementation of Twisted's Deferred pattern that accomplishes a similar goal to a cross-thread signal-slot mechanism. If someone doesn't come along and post a better solution, it might be worth a look: http://sourceforge.net/projects/deferred/