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.
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 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.
So if I understand correctly, If I have a class FunctionsClassthat inherits QObject and i set that class up on a Qthread called FunctionClassThreadby doing:
FunctionsClass classObj;
classObj.moveToThread( &FunctionClassThread );
FunctionClassThread.start();
From what I understand this method of setting up a thread will only handle the execution of slots in the FunctionsClass, which means the thread running FunctionsClass can be blocked if a slot in FunctionsClass for some reason has a infinite loop.
So my questions are: How can I run the functions of FunctionsClass on a thread not just the slots? Is there a way to place a whole object (functions, member variables, etc) on a thread for execution of code/data from that whole object only? And is my understanding of how the thread will handle the execution of slots correct?
When you execute a method of an object it is executed in the thread you're invoking the method. It doesn't matter where the QObject is living.
If you want to invoke a method so that it is executed in another thread asynchronously you'll have to handle the situation so that the message is posted, waits for the thread to be available (might be busy, it has to return control to the event loop first) and then, run the method.
This can be done using signals and slots, with the usual connection. If you don't want to use that mechanism, you can use QMetaObject, but you still have to declare those as slots. The static method invokeMethod, if called with Qt::QueuedConnection will invoke the method in the thread in which the object owning the method is living. You can also pass arguments to the method and returns values from it.
Consider that any data types you want to be able to pass from a thread to another need to be registered with qRegisterMetaType and must respect the conditions reported in there.
Methods of a class will execute in the context of the thread that calls them. If you move a QObject class to a thread (let's refer to it as worker thread), then only methods of that class that are called directly (or indirectly) from the run() method of the worker thread, will execute in the context of the worker thread.
If you want to call methods on that class from some other thread, but still have them run in the context of the worker thread, then you need some way to get a message to the worker thread so it can call the method you want. This is essentially what is achieved by Qt signals and slots when thread boundaries are crossed.
With a lot of extra work, there are two other ways you can do the same thing. First, QThreads have an event loop which is started by default if you don't override run(). You can create custom events that you can post to the event loop which can trigger activity in your class that will execute in the context of the worker thread.
The second way would be to call methods in your class from another thread that modify class fields that the worker thread monitors. You need to be sure that access to any of these fields is synchronized with some mechanism like a mutex.
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.
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.)