Basically I'm asking for any helpful information as to what must happen to make the following code thread safe. http://code.google.c...signal_slot.hpp
I'm not sure if the problem can be easily solved with the current implementation as a signal would probably have to be locked during any operation not to mention the destructor of tracked.
Lastly, any constructive criticism is welcome. For those who don't even link:
struct tracked
{
std::shared_ptr<std::function<void(std::uintptr_t)>> erase_callback;
std::unordered_map<std::uintptr_t, std::weak_ptr<std::function<void(std::uintptr_t)>>>
connections;
tracked ( ) : erase_callback(new std::function<void(std::uintptr_t)>)
{
(*erase_callback) = [this] (std::uintptr_t connection)
{
this->connections.erase(connection);
};
}
virtual ~tracked ( )
{
for (auto const& connection : connections)
{
if (connection.second.expired() == false)
{
(*connection.second.lock())(connection.first);
}
}
}
};
template <typename... Args> struct signal { signal ( ) = delete; };
template <typename... Args> struct signal<void(Args...)> : private tracked
{
signal ( ) : tracked ( )
{
(*erase_callback) = [this] (std::uintptr_t connection)
{
this->connections.erase(connection);
this->m_slot.erase(connection);
};
}
//------------------------------------------------------------------------------
template<typename T>
void connect(void(T::*callback)(Args...), T* instance)
{
std::uintptr_t hash = member_hash<T, Args...>()(callback, instance);
m_slot.emplace(hash, make_function<T, Args...>(callback, instance));
derived_tracked<T>(hash, instance);
}
void connect(void(*callback)(Args...))
{
m_free.emplace(reinterpret_cast<std::uintptr_t>(callback), callback);
}
//------------------------------------------------------------------------------
template<typename T>
void disconnect(void(T::*callback)(Args...), T* instance)
{
(*erase_callback)(member_hash<T, Args...>()(callback, instance));
}
void disconnect(void(*callback)(Args...))
{
m_free.erase(reinterpret_cast<std::uintptr_t>(callback));
}
//------------------------------------------------------------------------------
void operator() (Args... args) const
{
for (auto const& connection : m_slot)
{
connection.second(args...);
}
for (auto const& connection : m_free)
{
connection.second(args...);
}
}
private: //-----------------------------------------------------------------
template<typename T>
void derived_tracked(std::uintptr_t hash, typename T::tracked* instance)
{
connections.emplace(hash, instance->erase_callback);
instance->connections.emplace(hash, erase_callback);
}
template<typename T> void derived_tracked(...) { } // sfinae
std::unordered_map<std::uintptr_t, std::function<void(Args...)>> m_slot;
std::unordered_map<std::uintptr_t, std::function<void(Args...)>> m_free;
};
Edit: above code is for context. current code is at the link above.