简体   繁体   中英

QT Conditional signal emitting - efficiency

I allready have a bigger project and architecture and run into a situation with the QT signal-slot system with very homogenous signals and the problem: 1. Either many different signal mehtods with different names like

signals:
sig_1(bool b);
sig_2(bool b);
...
sig_n(bool b);

or: 2. emiting the difference as argument

signal:
sig(uint n, bool b);

and lets the slot method decide if n fits it's internal values

each options is worse that the other:

  1. awefull code, I would prefer more like a generic solution
  2. every slot has to check if it number will fit, so a row of everytime O(n) connections, when the moc allready goes through a switch-block where we can reach O(log n)

The situation: the emitter is a microcontroller-abstraction and gets informed on input changes. Many of the slot-classes just have one or two inputs connected and need to be informed about their changes. Structurally the emitting class should not depend on the slot-classes and therefore should not keep a list of it's listener or include a common super-class or interface of the listeners, so thats why I'm stick to the signal/slot system.

So my Question: Is there some kind of extension or argument in the sig/slot system or to the moc or have I missed something completely here?

there is a class in Qt called QSignalMapper that helps managing Many-to-One connections, but afaik it doesn't qutomatically solve a Many-to-Many problem

You could try doing away with the idea of direct (emitter-receiver) connections, and try using a shared data vector in the middle. Emit only one signal ("data updated"). Receivers will get notified about the update, and pull only the data they need from the shared data object (this can be as simple as a map if thread safety is not a concern).

If the data vector is small and relatively cheap to copy, you could simply emit the whole vector/map directly to everyone (as noted above, in Qt5 direct connections result in direct function calls, so this won't be all that slow)


Thanks to d.Candela: The Concept of Many-to-One, Many to Many helps a little bit to sort the Problem. My Problem was the missing One-to-Many. The solution is a templated manager-class, keeping a matrix with only sparse entries of 1. Every row is a bit of the input value, and the colums are representing the subscribers with the column-vector as their subscription-index. From here it is just bit shifting and masking. So the slots of the listeners are relaced by a templated vector in the manager and the signal source is connected to the manager. If there is a special case of a diagonalizable matrix (only unit subscription vectors) we can keep it sorted and go down to O(n^-2) from O(n).

You could create a class for managing all your different signal types, then emit objects of that class in your signals. Slots can examine the emitted object to see if they need to process it. Example code:

struct SignalInfo {
  string description;
  bool value1;
  int value2;
  //Etc
};

Then the signature of your signal would be:

void sig(SignalInfo);

and your slots might look like this:

void Handle_signal(SignalInfo info) {
  if (info.description == "type 1") {
    /*do something*/
  }
}

The advantage is that you can change the SignalInfo class without needing to change anything else. With that said, you could instead emit and receive references to SignalInfo objects, which would let you subclass SignalInfo for even more flexibility. Example signal and slot signatures would be:

void sig(SignalInfo&);

void Handle_signal(SignalInfo& info);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM