Signal-Slot Implementation — Part 4

C. Burak Ongay
brakulla
Published in
3 min readMay 15, 2019

In previous post, we implemented a base class for creating threaded classes.

Before just writing our new code, I want to introduce another problem. We introduced a threaded object and signal-slot mechanism can work between different threads. But we cannot force anyone to use this threaded object whenever they want to use signal or slot. So we need to provide a way to call the slot directly when a signal is emitted. To do so, I’ll introduce connection type.

When using with a threaded object, signals and slots can use these threads to operate between threads, this is a queued connection. When using without a threaded object, we can just use the signal and slot classes as they are now, as in this post. This is a direct connection.

We can introduce one more connection type, auto, for leaving the decision to the implementation automatically. It can determine the connection type itself by looking signal and slot classes belong to threaded object or not. In order to be able to look if they belong to a threaded object, we can introduce a private member variable `br_threaded_object *_parent` to signal and slot classes.

We introduced new private member variable `_parent` and initialized it on constructors. If they do not belong to any br_threaded_object, `_parent` can be initialized with `nullptr`.

And we can also add a new function to get the thread id of the root objects of these classes. By adding that, we are providing a way to determine the running thread of the objects of these classes.

So `getThreadId()` function returns its parent thread id if its parent exists, returns the calling thread id if not.

We already introduced connection type, but we didn’t use it. In connect function of signal class, we can pass the connection type. If it’s direct connection, it will call the slot function directly, or if it’s a queued connection, it will pass the slot function to br_threaded_object as event to be run in slot’s parent thread. If the connection type is given as auto, we can determine which connection to choose by looking signal’s and slot’s thread ids.

On queued connection, the slot will be passed to its parent class as event. However, we don’t have that function, yet. We can introduce a new function on slot to add itself to its parent as event. But I don’t want it to be public, because that function will be used exclusively by signal. So I’ll introduce it as private function of slot class, but define signal class as friend in slot class for signal object to be able to call this function.

The result is getting bigger:

I introduced two slot vectors instead of one to differentiate the direct and queued connected slots. And I introduced hasParent() function to slot for signal to query. If either one do not have a parent, then the connection is forced to be direct. If both have parent and the connection is given as auto, the connection type is deducted from thread ids of signal and slot objects.

In addition, I changed the emit function to check caller thread id and its parent thread id. If they are same, it calls direct slot function directly and adds queued slot functions to slot parent objects as events. If they are different, then these caller functions of signal is added to signal’s parent object as event to be called within signal’s parent thread.

This is the end of Signal-Slot Implementation blog series. We completely implemented the classes. You can reach the code from this link: https://github.com/brakulla/brutils/blob/master/include/brutils/br_object.hpp

This is a link to my GitHub repo with MIT Lisence. You can do anything you want with it. Just remember that, it may have some differences with this blog, since I constantly do improvements. Just ask if you have any questions, I’ll answer them.

--

--