How to create SignalHub in a QT application? - linux

There is a multi-threaded application on QT5. Threads emits signals to each other. For example, the button click signal in the GUI comes in three separate threads, and each thread performs its own function. Is there an easy way to connect all signals to some object, let's call it SignalHub? And this SignalHub will receive all signals from all threads or objects, and any thread or object can be subscribed to the desired signal? Something similar to DBus, but only for several threads within a single QT application? Each thread or object should not receive its own signal. The purpose of this is to reduce the amount of code (there are several threads in the application, and each has multiple signals and slots). And it would be ideal to connect the necessary signals to (and from) the SignalHub only in new object's constructor or new thread's constructor.

Signals are thread-safe. So are connect() and disconnect(). Meaning: you can literally declare any object you want to be your "signal hub" and just connect the slots across threads as you desire. To what threads the objects involved belong doesn't matter. No problems.
To avoid receiving signals an object sent itself, you can simply do something along those lines:
void MyObject::someSlot() {
if(sender() == this) return;
}

Related

What is the meaning of the term "event loop" w.r.t threads in Qt?

http://doc.qt.io/qt-5/threads-qobject.html#per-thread-event-loop
https://wiki.qt.io/Threads_Events_QObjects#Per-thread_event_loop
These two links talk about event loop. Please explain the "meaning" of the term "event loop" w.r.t threads in Qt?
An event loop is usually a loop that is run by the main thread to receive events that either originate from the system (e.g. GUI interaction, network events, timers, ...) or from other Qt components (e.g. QCoreApplication::postEvent(), ...). The event loop waits for new events to arrive in the event queue, then takes them out of the queue and sends them to their destination QObject where they are handled by an overridden QObject::event(QEvent*) (e.g. A QPushButton would handle a mouse press event by emitting pressed(), ...).
Per-thread event loops are a generalization of the concept above. This makes it possible to handle events in worker threads by introducing the concept of a QObject's thread affinity. Thread affinity is the thread in which a particular QObject should have its events handled (the thread from which QObject::event gets called for this QObject). In the big picture, this can be used to run asynchronous code in worker threads (since GUI code should be run only in the main thread). For example, you can run many asynchronous sockets and have QTimers to disconnect these sockets after some specified time of inactivity all in a single worker thread. Per-thread event loops are also essential for cross-thread signal-slot connections, since this kind of signal emissions is translated into QMetaCallEvents under the hood (to be delivered to its destination QObject).

Can Qt signals can be safely emitted from another QThread

I'm using some QThread in my application.
My objects "live" in different threads (their owner threads as Qt means it are different) and use signal/slots with queued connections to communicate.
Now, I have this problem :
Object "A" lives in QThread "A"
Object "B" lives in QThread "B"
Gui lives in the "main thread"
then :
Object "A" calls a method B::foo on "B" instance, from its own thread "A"
the ressources shared by this B::foo method are protected using a mutex, no problem here to execute B::foo from the thread "A"
inside the B::foo method, object "B" emit the signal barSignal
And I have some questions about his configuration :
Is it safe to emit a signal of object "B" from a thread which is not the "B" owner's QThread ?
Is it safe to use Qt::AutoConnection to receive this signal in a GUI object who lives in the "Qt main thread" ?
Is it safe to use a Qt::AutoConnection to receive this signal in a object "C" who lives in it's own QThread "C" ?
My test tends to say "yes" to everything.
By reading the Qt emit code, it seems to be ok.
But it didn't find anything in the Qt documentation about "emitting signal from a thread which is not the emitter's owner thread".
It's safe to emit signals from other threads, if you use auto or queued connections. Auto is deduced to be queued in situations where the signal is emitted in a thread in which the receiving QObject do not have affinity. Direct connections are not thread safe.
There is a "Signals and Slots Across Threads" section in the documentation that deals with emitting signals to objects in different threads.
Queued Connection - The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
also
The connection type can be specified by passing an additional argument to connect(). Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.
QObject::connect() itself is thread-safe.

Accessing shared data from a signal handler

I want to know if it is a good idea to access shared data from a signal handler. I mean consider the scenario of multi process system and multithreaded system with a single process. In multi process system, lets say I have the processes handle a particular signal and update certain shared variable or memory by the processes. Can I do that from the signal handler itself.
However, in the case of threads using pthreads, I don't think it is doable. http://maxim.int.ru/bookshelf/PthreadsProgram/htm/r_40.html. As given in this article, they have mentioned that it is not asynchronous signal safe and have suggested to use sigwait for that. I am not why it is not asynchronous signal safe. I mean lets say, I handle a signal by a thread and is in the signal handler routing. I acquire a lock on the shared memory to update it. In the mean time another signal of the same type arrives and another thread responsible for handling it executes the signal handler again. Here the signal handler is same for the process but it is called multiple time. The second time around, it cannot see the lock and updates/overrides the data. Is this the issue with multithreaded signal handlers using shared data.
I am a bit confused, in multi process systems, I have a copy of the signal handler for each process. But in multithreaded system, there is a single copy of the signal handler used by the multiple threads isn't it. So when multiple signals of the same type arrives and we have two threads that are responsible for handling it try to handle it, then both of them will try to execute the same piece of handler code? How does it all fit in?
I read through the article that you reference and found some interesting information in the "Threads in Signal Handlers" section. In that section, you'll see that they have a list of Posix function calls that can be made from within signal handlers. Then soon after that list, they mention the following:
But where are the Pthreads calls? They're not in either of these
lists! In fact, the Pthreads standard specifies that the behavior of
all Pthreads functions is undefined when the function is called from a
signal handler. If your handler needs to manipulate data that is
shared with other threads≈buffers, flags, or state variables≈it's out
of luck. The Pthreads mutex and condition variable synchronization
calls are off limits.
Notice the last sentence: "Pthreads mutex and condition variable synchronization calls are off limits"
The aforementioned functions that can be called from a signal handler are described as follows:
These functions have a special property known as reentrancy that
allows a process to have multiple calls to these functions in progress
at the same time.
The pthread synchronization functions dont have the special property known as reentrancy, so I imagine that if these functions (pthread_mutex_lock() for instance) are interrupted by an arriving signal, then the behavior is not "safe".
Imagine that your application calls pthread_mutex_lock(&theMutex) and at exactly that moment (that is, while in the pthread_mutex_lock() function) a signal arrives. If the signal handler also calls pthread_mutex_lock(&theMutex), the previous pthread call may not have terminated, so it cant be guaranteed which call to pthread_mutex_lock() will get the lock. So the resulting behavior will be undefined/undeterministic.
I would imagine that the call to sigwait() from a particular thread would guarantee that no important, non-reentrancy function calls may get interrupted, thus allowing calls to the pthread synchronization functions to be "safe".

Global variable declaration in Qt

I have made a Gui thread and a QTcpSocket thread in Qt.I want to access data
from QTcpSocket thread to Gui thread.How to solve it?
Do i need to declare some global variable and how?
The easiest way is to communicate via signal-slot connections. There is one QObject in each thread. The sending object has a signal, which is connected to the slot of the receiving object in the other thread.
In this setup, you make sure that the objects on both ends of the connections are configured to live in the correct threads. You might need to call QObject::moveToThread(). QObject also has a property where you can get the current thread (for debugging purposes in this case).
Then just establish the signal-slot connection as usual. Since both objects are in different threads, when the signal is triggered, a slot invocation event will be placed in the event loop of the receiving flag. This is explained in the Qt documentation, look for Qt::QueuedConnection.
The QTcpSocket is created from the gui thread.
So at that point the gui thread has a pointer to the socket object.
It then creates a connection between a slot in the gui and a signal in the socket.
In the socket object whenever you get data you simply emit a signal containing the data, which will be picked up by the gui thread.
You can pass any Qt type eg QString, QByteArray (or a raw pointer), through a signal/slot very efficiently. The details if signals between threads are also handled automatically.

Why are slots being called from the main thread?

I have a Qt application that has two threads: the main thread that handles the GUI and a second thread that manages network connections. Here is the thread code:
void thread::run()
{
QTcpServer server;
server.connect(&server,SIGNAL(newConnection()),this,SLOT(OnConnect()));
//...
}
When I put a breakpoint at the start of OnConnect() and debug the application, it announces that OnConnect() is being called from the main thread!
How can I have OnConnect() run in the same thread as the QTcpServer?
To give a more thorough answer, look a little deeper into how signal-slot connections and thread contexts interact. Basically, for more connections (auto-connect), the slot will be directly called if both the emitter and the receiver are in the same thread context, otherwise it will be a queued connection, and the slot will be run in the thread context of the object that contains the slot. In this case, it must be queued, which implies that your thread is part of the main application's thread context, not its own. This is reinforced by the documentation Qt provides for an overview of its threading, where it states that the QThread instance is "owned" by the thread context that created it, not the thread context that it represents. This means you have three main choices:
You can use moveToThread() to move the thread into its own context. Note that this may cause problems when deleting the thread unless you move it back to the context where it will be destroyed, and this can only be done in the source-thread context, so it would have to be done before the run function exited.
You can treat the QThread instance as a handle to the thread, not as being part of the thread itself. If you need things done in the context of the new thread, create a different object to handle those, and instantiate them in the context of the new thread (inside the run function). This is what I would recommend.
Force a direct connection. This means you would need to ensure the code running in the slot is thread-safe, ignoring Qt's built-in methods of making those functions thread-safe. This is what you have done.
It seems like the problem was that I wasn't passing Qt::DirectConnection as the last parameter of connect().
After adding that, it worked.

Resources