Why using QMetaObject::invokeMethod when executing method from thread - c++

I have following code:
class A : public QObject
{
Q_OBJECT
public:
A() : QObject()
{
moveToThread(&t);
t.start();
}
~A()
{
t.quit();
t.wait();
}
void doSomething()
{
QMetaObject::invokeMethod(this,"doSomethingSlot");
}
public slots:
void doSomethingSlot()
{
//do something
emit ready();
}
signals:
void ready();
private:
QThread t;
}
The question why from doSomething it must be call via QMetaObject::invokeMethod. I know that there is something with connection type. Could some one explain what is under the hood?

As you haven't specified a Qt::ConnectionType, the method will be invoked as Qt::AutoConnection, which means that it will be invoked synchronously (like a normal function call) if the object's thread affinity is to the current thread, and asynchronously otherwise. "Asynchronously" means that a QEvent is constructed and pushed onto the message queue, and will be processed when the event loop reaches it.
The reason to use QMetaObject::invokeMethod if the recipient object might be in another thread is that attempting to call a slot directly on an object in another thread can lead to corruption or worse if it accesses or modifies non-thread-safe data.

I like this trick:
void A:doSomethingSlot()
{
if (thread()!=QThread::currentThread()) {
QMetaObject::invokeMethod(this,"doSomethingSlot", Qt::QueuedConnection);
return;
}
// this is done always in same thread
...
emit ready();
}

Related

QRunnable emit signal and get sender from slot

QRunnable is destroyed by QThreadPool after it finishes. When I emit a signal from it and try to get the QRunnable object from slot using sender() it's NULL.
Minimal example:
// class MyRunnable : public QObject, public QRunnable
MyRunnable::run()
{
//... do some work
emit onFinished();
}
// constructor by request
MyRunnable::MyRunnable(QObject *parent) : QObject(parent),
m_someData(1),
{
}
...
private slots:
void onFinished()
{
MyRunnable* myRunnable = qobject_cast<MyRunnable*>(sender());
int val = myRunnable->getSomething(); // myRunnable is null and it crashes
}
...
// later I start it using some thread pool
MyRunnable* myRunnable = new MyRunnable;
connect(myRunnable, SIGNAL(onFinished()), this, SLOT(onFinished());
threadPool.start(myRunnable);
Is there any way I can specify when to delete this object? So I can safely access it's data members inside my slot?
You want to access your object's members after it has been destroyed. Obviously, you can't safely do that.
Plus, casting sender() to access it directly is a danger sign - both in terms of unnecessary coupling and in terms of thread safety.
Instead, you probably want to copy the relevant members into the signal:
MyRunnable::run()
{
//... do some work
emit onFinished(getSomething());
}
and simply use the results in the listener.
If you really believe you must control the lifetime of the runnable, you could observe that
the thread pool takes ownership of the runnable if runnable->autoDelete() returns true
So you could override autoDelete() to return false, then call its deleteLater() method from your slot. Take care accessing its members directly, as it is still an a thread-pool thread.
The runnable is processing a request and producing a response. Factor those out and the problem is solved:
struct FooRequest;
struct FooResponse;
using FooResponsePtr = std::shared_ptr<FooResponse>;
class Foo : public QObject, public QRunnable {
FooRequest m_req;
protected:
void run() override {
std::shared_ptr<FooResponse> rsp;
/* ... */
emit hasResponse(rsp);
}
public:
Foo(const FooRequest & req) : m_req(req) {}
Foo(FooRequest && req) : m_req(std::move(req)) {}
Q_SIGNAL void hasResponse(const FooResponsePtr &);
static void main() {
qRegisterMetatype<FooResponsePtr>();
}
};
Q_DECLARE_METATYPE(FooResponsePtr)
int main() {
Foo::main();
...
};
You could also make FooResponse an explicitly shared class using QExplicitlySharedDataPointer, making it like other cheap-to-copy Qt value classes. The access would then be direct, without a need for std::shared_ptr. The explicit sharing is cheaper than implicit sharing, and makes more sense if you don't intend to retain the copy-on-write behavior of implicit sharing.

( QNativeSocketEngine) QObject: Cannot create children for a parent that is in a different thread

I'm having a problem which was ask here for a similar situation a couple of times, however I couldn't find the solution in those topics.
I'm having a main class where I'd like to extend it with a qt-network support, and this by an additional class. Let me break the source code down for you to the relevant parts:
main class
.h
class MainClass: public QObject{
Q_OBJECT
public:
[...]
private:
NetworkSupport * netSupport;
};
.cpp
MainClass::MainClass()
{
[...]
netSupport
netSupport = new NetworkSupport(this->thread());
netSupport->start();
[...]
}
network class
.h
class NetworkSupport : public QThread
{
Q_OBJECT
public:
NetworkSupport(QThread *mainThread);
~NetworkSupport();
QByteArray readData();
void sendData(QByteArray *msg);
public slots:
void acceptConnection();
void receive();
void run();
private:
QByteArray curMessage;
QThread* libThread;
QEventLoop initWlan;
protected:
QTcpServer server;
QTcpSocket* client;
};
.cpp
NetworkSupport::NetworkSupport(QThread* mainThread)
{
libThread = mainThread;
server.moveToThreaD(libThread);
server.listen(QHostAddress::Any, 5200);
QMetaObject::invokeMethode(&initWlan, "quit", Qt:QueuedConnection);
initWlan.exec();
}
void NetworkSupport::run(){
connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
}
void NetworkSupport::acceptConnection()
{
client = server.nextPendingConnection();
client->moveToThread(libThread);
if (client->state() == QAbstractSocket::ConnectedState)
connect(client, SIGNAL(readyRead()), this, SLOT(receive()));
}
void NetworkSupport::receive()
{
curMessage = client->readAll();
}
void NetworkSupport::sendData(QByteArray* msg)
{
if(client->state() == QAbstractSocket::ConnectedState)
{
client->moveToThread(libThread);
printf("Sending a message %s\n",msg->data());
client->write(*msg);
client->waitForBytesWritten();
}
}
I know I usually don't need to specifiy the moveToThread() this much, but it doesn't change a thing in the end, if all of them are there or removed.
However when executing I get the error message at client->write(*msg) in sendData(), that is:
[...]
Sending a message ?r
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QnativeSocketEngine(0x2afc660), parent's thread is QThread(0x1b59210), current thread is QThread(0x7f6a70026b60)
QSocketNotifier: Can only be used with threads started with QThread
[...]
It does look like a warning, since the the program is still in execution afterwards, but I don't receive any messages from the client (i.e. receive() gets never executed), which is I guess because of the last line from the error message.
Could it be that this error message is just misleading and if so what's it actual meaning, or did I do something completely wrong?
You are doing so many things wrong in this code that I'm not sure what to start with.
NetworkSupport::NetworkSupport(QThread* mainThread)
{
libThread = mainThread;
server.moveToThreaD(libThread);
This will do nothing. server is already in same thread as MainClass instance
server.listen(QHostAddress::Any, 5200);
Server will start to listen on same thread as MainClass
QMetaObject::invokeMethode(&initWlan, "quit", Qt:QueuedConnection);
initWlan.exec();
This mocks me a lot. This will simply start event loop and quit it almost immedietly.
}
void NetworkSupport::run(){
connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
}
This will simply run in new thread, call connect and quit thread right after connect statement - your thread will not be running anymore after connect. Also slot acceptConnection will be probably called in same thread as MainClass. I wonder when and where is MainClass created.
Seems for me like you're struggling with to many things at same time. You probably read somwhere, that you should use separate thread for network communicaton, so you won't block other threads. Try single thread approach first. When you get that working, then you should think how to utilize other thread for what you need.
Bonus question: Is this code some kind of plugin for application that may not have Qt eventloop at all? Or is it part of the full-stack Qt application?
There are a few misunderstandings in your code how Qt networking and multi threading works.
First, in Qt docs they say on QTcpServer::nextPendingConnection():
The returned QTcpSocket object cannot be used from another thread. If
you want to use an incoming connection from another thread, you need
to override incomingConnection().
So, you must create your own Server class, that inherits from the QTcpServer, and override incomingConnection() there. In that overriden method you have to post the socket descriptor to other thread where your TCP client will live processing that connection. In this simple example we just emit a signal.
signals:
void myNewConnectionSignal(DescriptorType);
protected:
void incomingConnection(DescriptorType descriptor)
{
emit myNewConnectionSignal(descriptor);
}
Second, what is NetworkSupport thread for? I guess, you want your server object to live and work there? If so then you must rewrite it in other way. Below is the server part only. Note, that QThread already has a QEventLoop and you can use it via exec() in your run().
...
protected:
MyServer *server;
...
NetworkSupport::NetworkSupport()
{
// this is called in the main thread, so "this" lives in main thread
server=0;
client=0;
// say thread to start, but it will be actually started within run()
start();
// sometimes it is recommended to wait here for the thread started
}
NetworkSupport::~NetworkSupport()
{
// this is called in the main thread, say this thread to stop running
quit();
// wait for completion
wait();
}
void NetworkSupport::run()
{
// this is called in server thread
server=new MyServer();
if (server->listen(QHostAddress::Any, 5200))
{
// connect our new signal to slot where we create and init the TCP client, note that Qt::QueuedConnection is used because we want acceptConnection to run in the main thread
connect(server, SIGNAL(myNewConnectionSignal(DescriptorType)), MyClientsPool, SLOT(acceptConnection(DescriptorType)), Qt::QueuedConnection);
// go for infinite event loop
exec();
}
else
{
// do you always ignore errors?
}
// the thread is stopped, let's destroy the server in the thread where it was born
delete server;
server=0;
}
Client is living and working in your main thread. You must not call its methods directly from other threads. NetworkSupport lives in the main thread as well: yes, it incapsulates and manages some other thread but as an QObject itself it lives in the thread we created it in. The methods below are always executed in the main thread because we connected server's signal to NetworkSupport::acceptConnection() using Qt::QueuedConnection which says to Qt that we want the slot to be invoked in the thread where its QObject lives.
private slots:
void socketDisconnected();
...
void NetworkSupport::socketDisconnected()
{
if (client)
{
client->deleteLater();
client=0;
}
}
void NetworkSupport::acceptConnection(DescriptorType descriptor)
{
QTcpSocket* client=new QTcpSocket(this);
client->setSocketDescriptor(descriptor);
connect(client,SIGNAL(disconnected(),this,SLOT(socketDisconnected());
connect(client,SIGNAL(readyRead(),this,SLOT(receive());
}
void NetworkSupport::receive()
{
if (client)
curMessage = client->readAll();
}
void NetworkSupport::sendData(QByteArray* msg)
{
if (client)
{
client->write(*msg);
client->waitForBytesWritten();
}
}
UPDATE
If we just want to hide all network works inside the thread. Note, in the example below there is little error handling and a lot of messages data copies. You might want to optimize it for production.
// private container class incapsulated and working in the thread
class NetworkThreadContainer : public QObject
{
Q_OBJECT
public:
NetworkThreadContainer(QObject* parent=0):QObject(parent),client(0)
{
if (server.listen(QHostAddress::Any, 5200))
{
connect(&server, SIGNAL(newConnection()), this, acceptConnection());
}
else
{
// don't you want to throw exception here?
}
}
public slots:
void sendDataToClient(const QByteArray& barr)
{
if (client)
{
client->write(msg);
client->waitForBytesWritten();
}
}
void acceptConnection()
{
if (!client)
{
client = server.nextPendingConnection();
connect(client, SIGNAL(readyRead()), this, SLOT(receive()));
}
else
{
// what will you do with more than one client connections or reconnections?
}
}
void NetworkSupport::receive()
{
if (client)
{
QByteArray curMessage = client->readAll();
emit messageReceived(curMessage);
}
}
signals:
void messageReceived(const QByteArray&);
public:
QTcpClient* client;
QTcpServer server;
};
// thread class visible to outer program
class NetworkThread : public QThread
{
Q_OBJECT
public:
NetworkThread(QObject* parent=0):QObject(parent)
{
start();
}
~NetworkThread()
{
quit();
wait();
}
bool sendDataToClient(QByteArray* barr)
{
bool ok=false;
// async send data to container's thread
mutex.lock();
if (container)
{
ok=true;
QMetaObject::invokeMethod(
container,
"sendDataToClient",
Qt::QueuedConnection,
Q_ARG(QByteArray, *barr)
);
}
else
{
// container either is not ready yet or already destroyed
}
mutex.unlock();
return ok;
}
signals:
void messageReceived(const QByteArray&);
protected:
void run()
{
mutex.lock();
// I would suggest to catch exception here and assign the error result to some variable for further processing
container=new NetworkThreadContainer();
mutex.unlock();
connect(container,SIGNAL(messageReceived(QByteArray),this,SIGNAL(messageReceived(QByteArray)),Qt::QueuedConnection);
exec();
mutex.lock();
delete container;
mutex.unlock();
}
private:
QMutex mutex;
QPointer<NetworkThreadContainer> container;
};

Qt objects can still be deletedLater() without event loop?

I'm confused about threads and event loops in Qt.
A QThread normally runs exec() in run(). But when you override run(), there will not be an event loop.
This (older) doc states that calling deleteLater() on objects that are created in a thread without an event loop doesn't work:
If no event loop is running, events won't be delivered to the object.
For example, if you create a QTimer object in a thread but never call
exec(), the QTimer will never emit its timeout() signal. Calling
deleteLater() won't work either. (These restrictions apply to the main
thread as well.)
However, look at the following code:
class MyObject : public QObject
{
Q_OBJECT
QString content;
public:
MyObject(QObject *parent = 0);
~MyObject();
};
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
signals:
public slots:
};
MyObject::MyObject(QObject *parent) :
QObject(parent),
content("foobar")
{}
MyObject::~MyObject()
{
// This code is still executed before I close the program. How?
qDebug() << "Destroying MyObject";
}
MyThread::MyThread(QObject *parent) :
QThread(parent)
{}
void MyThread::run()
{
// Creating a heap object in a thread that does not have
// an event loop (because I reimplemented run()).
MyObject * objectification = new MyObject();
sleep(1);
objectification->deleteLater();
}
So why does the deletelater() call still post an event that is picked up?
As the Qt docs state for deleteLater: -
Since Qt 4.8, if deleteLater() is called on an object that lives in a thread with no running event loop, the object will be destroyed when the thread finishes.
The object is still being deleted when no event loop exists. If you look at the source code for QObject::deleteLater, you'll see that an event is posted:-
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
So, let's look at what happens when a thread is deleted. QThreadData's destructor includes this:-
for (int i = 0; i < postEventList.size(); ++i) {
const QPostEvent &pe = postEventList.at(i);
if (pe.event) {
--pe.receiver->d_func()->postedEvents;
pe.event->posted = false;
delete pe.event;
}
}
As we see, although there's no event loop, the event list is still available.
If we look more closely into QThreadPrivate (just taking one platform as an example, in this case unix), you'll see that when the thread finishes, it forwards all deferred deleted messages, so they can continue to be processed:
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);

SIGNALS and SLOTS in QT5

I've encountered a following issue:
I have a GUI element class and a Thread class. I would like to exchange signals between them. However it only works in one direction. I can successfuly send a signal from main GUI window to the thread. However when I want to send a signal from the thread to the process that calls the thread, but it doesn't work. Here is how I do it:
bool GfxMapItem::mapSwitch(int seqidx)
{
...
importMapThread_ = new ImportMapThread(sequence_->item(seqidx));
connect(GUI_UI->analExportButton, SIGNAL(clicked()), importMapThread_, SLOT(interrupt1()), Qt::QueuedConnection); //<-- this one works perfectly
connect(importMapThread_, SIGNAL(progress(int)), this, SLOT(loadMap(int)), , Qt::QueuedConnection); // <-- this one unfortunatelly doesn't
...
}
The thread code is very simple and it only emits the signal (I've check that it works when I connect the thread with itself).
void ImportMapThread::run()
{
QLOGX("Running ImportMapThread...");
QLOGINC;
emit this->progress(100);
QLOGX("Stopping ImportMapThread...");
}
The thread header looks like the one below:
class ImportMapThread : public InterruptibleThread
{
Q_OBJECT
private:
...
protected:
...
public:
ImportMapThread(SeqItem *p);
signals:
void progress(int value);
void progressReset(int value);
public slots:
virtual void interrupt1();
void loadMap();
protected:
virtual void run();
};
And the class that calls that thread looks like this:
class GfxMapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
...
signals:
void mouseOutside();
void mouseMove(const QPointF &pos);
private slots:
void loadMap(int);
protected:
...
};
Any ideas? Please, I've ran out of ideas.
I believe, you should call exec in your run-implementation. Exec starts event-loop which should allow to send signals.
Take a look at:
int QThread::exec() [protected] Enters the event loop and waits until
exit() is called, returning the value that was passed to exit(). The
value returned is 0 if exit() is called via quit(). It is necessary to
call this function to start event handling.
I hope this helps.
Solved! It turned out that only the GUI elements can communicate with the threads. The thread can be inherited from other type of the thread and there isn't any problem neither with the signals nor the slots. The problem was laying in the object GfxMapItem. For some reason it just couldn't handle normal communication.

Is it possible to implement polling with QThread without subclassing it?

I have a class, which is an abstraction of some device.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start() and Stop() are called from GUI thread. Start() begins new thread, which runs MsgLoop(). It looks like this:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
When Stop() is called, program should return from MsgLoop() and stop the thread. How can I implement this with QThread without subclassing it?
Generally you have to decide who will be responsible for managing the thread. Is it the Device or the main window? Or possibly some device manager. In your case the Device should probably manage its own thread, so if you don't want to subclass it, use composition:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
NOTE: the thread stopping will only work if ReadMsg really is non-blocking. If you later decide to switch to blocking read (and that would probably be appropriate for most cases), you will have to figure out another way how to stop your thread.
If you look at this link you can see that it is possible to run a method in a separate thread without subclassing a QThread.
However what you are asking is running a message loop forever.
If you follow the given example you can run your loop without subclassing but the QThread object will never enter into its own message loop cause it will never return from your slot. So here is an example but I think it would be a bad design
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
I am afraid you have to subclass a QThread if you want to run a forever loop.
IMHO you shouldn't. Polling requires being in a forever loop. You must do this in QThread's run function so there is no way to re-implement a function without sub-classing first. Even if you were to try and workaround it with a single shot timer I don't recommend it. You are better off(this is how i like to do it) sub-classing QThread, calling moveToThread(), not call exec() and put a forever loop in run. For an example of this look at the Fortune Blocking Client example from qt. If you don't call moveToThread() on QThread then the QThread object still resides in the GUI main thread and they both share the same event loop (which is bad when using polling functions). Calling moveToThread(QThread) without calling exec() means the QThread will not have an event loop(which is good in your case). Calling exec() would start it's own event loop but is not used for polling schemes and you would leave the run function.