I have a Qt application that was developed using Qt Creator and the GUI tool that accompanies it. I have a main thread, TheGui and a worker thread that is created by the main thread, WorkerThread (called thread).
The problem I'm having is when I create a slot in the GUI by using
public slot:
void updateTable(string str);
within the header file of the GUI and signal void sendList(string str); within the header file of the worker thread, the slot never gets called. I connected the two using
connect(&thread, SIGNAL(sendList(string str),
this, SLOT(updateTable(string str)));
within the constructor in the GUI cpp file. I did something similar except with the slot in the worker thread and signal from the GUI and it worked fine. I know from using the debugger that the signal sendList is indeed getting called, it is just never going into it.
Any thoughts?
Because the signal and the slot are on distinct threads, the connection between them has the Qt::QueuedConnection type. And for queued connections, Qt has to be able to save a copy of the signal parameters, to pass them later to the slot.
So, to inform Qt that the type is copyable, you have to register it with Qt's meta-object system (see QMetaType) like this:
// This macro call should be put in one of your .h files
Q_DECLARE_METATYPE(std::string)
// You should call this function before any (queued)
// signal/slot connection involving the type
qRegisterMetaType<std::string>();
The parameter name shouldn't be included in the QObject::connect call, and the type names should be exactly the same as the ones you passed to Q_DECLARE_METATYPE:
connect(&thread, SIGNAL(sendList(std::string), this, SLOT(updateTable(std::string)));
You can also use QString or QByteArray, which are already registered, instead of std::string, since these functions are slots and signals and as such are already Qt specific.
Sure that connection is actually made? If there are any problems with connect call, there is usually some debugging output about it on cerr.
Secondly, I think you have a typo - if you copied connect call from your code, then know that you have parenthesis missing around SIGNAL - should be
connect(&thread, SIGNAL(sendList(string)), this, SLOT(updateTable(string)));
Thirdly, what is that you are passing as signal/slot parameter? Is it std::string? Connections between threads must be queued connections. Queued connections can use as parameters only types declared with Q_DECLARE_METATYPE macro, and registered with qRegisterMetaType. As far as I know, Qt by default doesn't declare those for std::string, as it prefers QString. If you didn't add those to your code, it might be the reason for failure.
Related
This question already has answers here:
How do I execute QTcpSocket in a different thread?
(5 answers)
Closed 3 years ago.
I am moving some sockets from main thread to worker thread and processing readyRead(), close(), write() etc. on the new thread. Rarely I see below dangerous warning:
"QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread"
Usually the execution after this warning results in undefined behaviour (crash / uncaught exception / normal).
Have checked all the signal/slot to the socket and they seem proper. From my experience, usually the above warning will be frequent or quick if there is any coding irregularity.
Now I am suspecting if moveToThread() does its job as expected or not! Because from QEvent documentation a QEvent::ThreadChange is raised as the last event on the current thread during this function call.
The object is moved to another thread. This is the last event sent to this object in the previous thread. See QObject::moveToThread()1.
1 A QEvent::ThreadChange event is sent to this object just before the thread affinity is changed. You can handle this event to perform any special processing.
In my code, I am not checking for this event. Rather I assume that, once the moveToThread() is finished, the thread affinity is changed and the new "signal/slot" on the object is guaranteed on the new thread.
Question:
Is it safe to move the sockets to another thread?
Will moveToThread() assure that the signals on that object are also moved to the new thread just after this function?
How should it be designed to assure no threading irregularity with Sockets?
BTW, in the latest Qt debugger it lands on following code segment:
// qsocketnotifier.cpp
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread");
return;
}
Below is the stack frame for the main thread:
Below is the stack frame for the worker thread, which halts on the logging:
Qt sockets are NOT supported with moveToThread() idiom!!!
I wish Qt had documented this fact as LOUD as above. I have spent weeks of debugging an issue which is not meant for fixing. Socket moveToThread() issue is so complicated, that it doesn't happen consistently. I could reproduce it consistently only after testing a customised QTcpServer subclass with lots of socket open/close scenario.
Later I came across this post: How do I execute QTcpSocket in a different thread?. This answer explicitly states that sockets are not supported for the movement across the threads.
Here are the documentations from QTcpServer
Note: 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().
Note: If you want to handle an incoming connection as a new QTcpSocket object in another thread you have to pass the "socketDescriptor" to the other thread and create the QTcpSocket object there and use its setSocketDescriptor() method.
Probably this will apply to the QWebSocketServer too!
So the best approach is to overload incomingConnection() and call its internal in another thread.
void MyTcpServer::incomingConnection (qintptr socketDescriptor) override
{
emit SignalToDifferentThread(socketDescriptor);
}
If done so, the addPendingConnection() and nextPendingConnection() idiom may not be required, even though it's mentioned in a note.
Note: If another socket is created in the reimplementation of this method, it needs to be added to the Pending Connections mechanism by calling addPendingConnection(). (<-- this may not apply for the sockets in different thread)
QWebSocketServer is stricter than QTcpServer
This is another fact, which wasted more time for me. In QTcpServer, we can overload the incomingConnection() and pass on the socket descriptor to another thread to create a socket. However, QWebSocketServer doesn't have such overload. Mostly because, QSslSocket received in QTcpServer gets upgraded to QWebSocket and passed on to the QWebSocketServer via its handleConnection() method.
So QWebSocket must be created where QWebSocketServer resides!. Hence in whichever threads, we want a QWebSocket to be created, all those threads need to have an object of QWebSocketServer. Idiomatically we can have one QTcpServer listening on a single port and can keep passing its QTcpSockets (upgraded to QWebSockets) to these various threads' QWebSocketServers in a load balancing way.
A message to Qt developers
I wish that, you can save lot of time of the developers relying on the Qt library by a simple compilation error. This will negate all the wrong articles floating around internet which suggest how to use moveToThread() on a QTcpSocket. Just introduce below method:
class QTcpServer / QTcpSocket / QWebSocketServer / QWebSocket : public QObject
{
Q_OBJECT
...
// Create this object in a desired thread instead of moving
private: void moveToThread (QThread*) = delete; // hiding `QObject::moveToThread()`
};
Update: Raised QTBUG-82373.
A quote from the docs, that provides the answer:
Warning: This function is not thread-safe; the current thread must be
same as the current thread affinity. In other words, this function can
only "push" an object from the current thread to another thread, it
cannot "pull" an object from any arbitrary thread to the current
thread. There is one exception to this rule however: objects with no
thread affinity can be "pulled" to the current thread.
I'm wrapping libcommuni, which uses Qt, in a different DLL project, which doesn’t use Qt. As far as I’ve been able to tell, I need to run the Qt message pump (via QCoreApplication) to make sure networking, signals, etc. work properly. However, I’m running in to some problems figuring out how to do just that.
Basically, I want to spin up a thread in the DLL, which calls QCoreApplication::exec() and pumps all the Qt events. I then want to marshal external calls to the DLL, which are on a different thread, to the Qt main thread, so I can safely use libcommuni.
It looks like the recommended approach is to use signals and slots for this, but I’ve been unable to get that to work. I create a signal on the QObject class that is called via the DLL and I connect it to a slot on the QThread that runs the Qt message pump. However, if I specify Qt::QueuedConnection when connecting the signal and slot, the message is never delivered when I emit the signal. If I omit Qt::QueuedConnection altogether, the slot is called immediately on the calling thread rather than the Qt main thread.
I’ve also tried explicitly calling QCoreApplication::postEvent() on the DLL thread to send an event to the Qt main thread, but event(QEvent) is never called in the target QThread.
Any ideas on what I’m doing wrong here? I'm guessing I'm not quite understanding Qt's threading model.
When you use QObject::connect without specifying connection type - it uses Qt::AutoConnection, which turns into Qt::DirectConnection if the signal and slot are in a single thread, or into Qt::QueuedConnection, if they are in different threads. So, in your case, I can say, that for the moment, when you connect your signal with your slot, the objects, they belong to, are located in one thread.
In order to make Qt::QueuedConnection work, you need an event loop in a thread, which contains slot.
There are two main ways of using QThread:
You can derive QThread and rewrite QThread::run. In that case you should do several things:
When creating your thread's object, do not specify parent; remove this object manually.
In your thread's constructor call moveToThread(this).
In your thread's run method call exec after all initialization, but before all removal; thread will leave exec right after you call QThread::quit.
You can derive QObject, create QThread object, and call QThread::moveToThread on your object (which, by the way, should be created without specifying parent) before calling QThread::start.
In your case I would recommend using the second method.
That is about threads, but I am not quite sure, your problem isn't connected with QCoreApplication::exec.
I'm trying to determine how calling QObject slots or Q_INVOKABLE methods from QML for a QObject that lives in another thread works, and whether or not its safe to do so.
Assume there's a MainThread and ThreadA. QObjectA lives in ThreadA. The QML engine/gui/everything lives in the MainThread. I expose QObjectA to the QML engine using
declarativeView->setContextProperty("someObj",ObjectA)
Now in a QML file, I call
someObj.someMethod();
Where someMethod is a slot or is Q_INVOKABLE. I'd like to know which thread actually executes the function. If it's MainThread, that would be a bad thing, and calling a method like that across threads would be dangerous. If it was executed by ThreadA however, all would be well.
Based on this documentation: http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html, I'm assuming that QMetaObject::invokeMethod() is used to call the QObject function. That documentation (http://doc.qt.nokia.com/4.7-snapshot/qmetaobject.html#invokeMethod), shows that there are different connection types available, just like with Qt signals and slots.
I'd like to know if Qt's qml engine automagically chooses the right type for the situation when invoking C++ methods from QML across threads, and if so, calling methods for objects that live in other threads from QML is an acceptable practice.
As it became apparent a while ago, QML doesn't seem to be able to go across threads.
So one needs to implement a C++ side intermediate object that lives in the main thread to dispatch calls to objects in other threads.
QML object -> object in a different thread // doesn't work!!!
QML object -> C++ mediator object -> object in a different thread // WORKS!!!
Basically, "transcending" threads must happen in C++ entirely, thus the need of a mediator object.
I guess the someMethod will be executed in ThreadA since the object lives in that thread.
But normally if this gives a problem, then I would do something like this.
connect(&threadA, SIGNAL(started()), someObj, SLOT(someMethod());
But to start that ThreadA we need one more CppObject to link QML and CPP.
You can use this->thread(); or QThread::currentThreadId(); inside the slot to get the thread the slot is working in. It will always be the thread, the ObjectA was created in (if there was no moveToThread()).
The Qt-Engine will select the right Qt:ConnectionType by determine call and called thread.
Extra tip: You can use GammaRay or ThreadSanitizer to see current direct connections across threads.
QML logic is event-driven and all invokes are parts of JavaScript functions. JS functions may be event handlers (for ex. UI event handlers) or may be invoked somewhere in C++ code if you wrap them in QScript object. Also you can invoke them in JavaScript WorkerTherad. That is why only you can provide an answer, where does someObj.someMethod() invokation take place.
I have my main form made Qt Designer and inheriting from QMainWindow and the UI. I need to have other threads running, and I need those threads to change things on the main form, eg progress bars, LCDs.
How do I give the other thread access to the widgets on the main form?
Thanks for any help.
Using signal/slots.
Trolltech introduces from 4.x a threadsafe mechanism for signaling using for example the
Qt::BlockingQueuedConnection parameter in connect() function.
For more details see:
http://lists.trolltech.com/qt-interest/2007-03/thread00260-0.html
As Flavius Suciu has mentioned, you can use a cross-thread signal/slot connection. They can also carry arguments, however, if you don't pass just fundamental types or Qt types as signal parameters but, say, your own custom struct, you need to tell Qt about them this way:
namespace MyNamespace { // if any...
struct MyClass { /* ... */ };
} // if any
Q_DECLARE_METATYPE( MyNamespace::MyClass )
This allows MyClass to be stuffed into QVariants, which is what Qt uses internally to ship copies of the signal arguments over thread boundaries.
You might also need to call
qRegisterMetaType<MyNamespace::MyClass>();
somewhere it's bound to be executed before any signal/slot cross-thread connection is attempted (e.g. in main(), or your QThread subclass constructor).
See the docs of Q_DECLARE_METATYPE
I'm trying to run a method on the GUI thread using QMetaObject::invokeMethod, which returns true. But, if I use Qt::QueuedConnection my method never gets called (even if invokeMethod returns true).
This is what I'm using:
QMetaObject::invokeMethod(this, "draw_widgets", Qt::QueuedConnection)
I don't get any error messages or anything...
If I use Qt::AutoConnection or Qt::DirectConnection the method does get called, but from the same thread of course. Not from the GUI thread, which is what I need.
draw_widgets is a public slot of type void draw_widgets()
and my class inherits QObject and uses the Q_OBJECT macro as well.
I would appreciate any help on this, or on how to check why the method is not being called.
Thanks.
The "true" is telling you the message was successfully queued. That doesn't mean the queued message was ever processed...
Let us say your program has 10 threads (Thread1-Thread10). You queue a message from Thread7. Which thread will it be queued to? And when will items on this queue be processed?
The answer is that every QObject has something called Thread Affinity, and this is the thread where a queued slot will be run. The default affinity is to the thread where the object was created (but you can change it with QObject::moveToThread().)
If you want to queue something to the GUI thread, then the object specified by your this pointer should have the GUI thread's affinity. You can check this with the QObject::thread() method.
But in any case, no matter what thread you queue to... you must have some kind of message pump running on that thread. Look at for instance QThread::exec(). If your thread affinity is to the GUI then presumably this is already the case because you are running the app's exec.
(As a sidenote, direct calls to QMetaObject::invokeMethod are usually unnecessary. You can create a signal and tie it to a slot, then emit the signal in lieu of the invoke.)