I have some problems designing a Signal/Slot system in C++11.
My main design goals are: simple but still offering some features and thread safe. My personal opinion on a Signal/Slot system is that emitting should be as fast as possible. Because of that I try to keep the slot list inside the signal tidy. Many other Signal/Slot systems leave disconnected slots empty. That means more slots to iterate and checking slot validity during signal emission.
Here is the concrete problem:
Signal class have one function for emitting and one function for disconnecting a slot:
template<typename... Args>
void Signal<void(Args...)>::operator()(Args&&... args)
{
std::lock_guard<std::mutex> mutex_lock(_mutex);
for (auto const& slot : _slots) {
if (slot.connection_data->enabled) {
slot.callback(std::forward<Args>(args)...);
}
}
}
template<typename... Args>
void Signal<void(Args...)>::destroy_connection(std::shared_ptr<Connection::Data> connection_data)
{
std::lock_guard<std::mutex> mutex_lock(_mutex);
connection_data->reset();
for (auto it = _slots.begin(); it != _slots.end(); ++it) {
if (it->connection_data == connection_data) {
*it = _slots.back(); _slots.pop_back();
break;
}
}
}
This works fine until one tries to make a connection that disconnects itself when signal i emitted:
Connection con;
Signal<void()> sig;
con = sig.connect([&]() { con.disconnect(); });
sig();
I have two problems here:
- The emit function must probably be redesigned because slots can potentially be removed when iterated.
- There are two mutex locks inside the same thread.
Is it possible to make this work (maybe with recursive mutex?), or should I redesign the system to not interfere with slots list and just leave empty slots (as many other similar projects do) when disconnecting the signal?
Aucun commentaire:
Enregistrer un commentaire