Jump to content

  • Log In with Google      Sign In   
  • Create Account


ApEk

Member Since 01 Jun 2012
Offline Last Active Feb 06 2014 11:52 PM
-----

Topics I've Started

signal slot and thread safety

07 November 2012 - 03:07 PM

Hello, I'm currently working on a very small signal slot implementation and have an initial version released, however, the code will probably fail in any concurrent scenarios.
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.

PARTNERS