Jump to content

  • Log In with Google      Sign In   
  • Create Account

signal slot and thread safety


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 ApEk   Members   -  Reputation: 500

Like
0Likes
Like

Posted 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.

Edited by ApEk, 08 November 2012 - 10:01 PM.


Sponsor:

#2 ApEk   Members   -  Reputation: 500

Like
0Likes
Like

Posted 08 November 2012 - 05:25 PM

Well got around to doing some performance testing against two other implementations, sigc++ and boost::signals.
However, still wondering how the heck to make it thread safe.

Posted Image
Higher is better. x axis is input size where there are N connections made and N signals fired.

#3 wqking   Members   -  Reputation: 756

Like
0Likes
Like

Posted 08 November 2012 - 08:23 PM

AFAIK, Boost::signals is not thread safe, Boost::signals2 is. Did you check it? You can just search where and how it puts mutex around.

http://www.cpgf.org/
cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.
v1.5.5 was released. Now supports tween and timeline for ease animation.


#4 ApEk   Members   -  Reputation: 500

Like
0Likes
Like

Posted 08 November 2012 - 08:55 PM

I have done research on current libraries. All of them make me say why? I'm about to just store a mutex in tracked and lock for any operation. Then instead of weak_ptr::expired do weak_ptr::lock and test the shared_ptr then lock the mutex inside of the erase callback?

Edit: saving thread safety for another time. could probably end up wrapping up the underlying data structure and add locking.

Edited by ApEk, 07 December 2012 - 02:47 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS