• Advertisement
Sign in to follow this  

Singleton Help

This topic is 3461 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, I'm going to use a singleton pattern similar to the one by Scott Milas for things like CGraphics, CInput, CAudio because if more than one of these objects is lying around at the same time it currently completely flips. Now I've written it and it works single-threaded, I've tried to synchronize it, however I'm not sure wether its completely thread-safe yet.
template <class T> class CJT::Singleton
{
private:
	static T* Instance;
	static CCriticalSection CriticalSection;
public:
	Singleton( void )
	{
		// Enter critical section, modifys static objects
		CriticalSection.Enter();

		// Check that the singleton hasn't already been created
		if(Instance != NULL)
		{
			// Make sure the critical section is not orphoned
			CriticalSection.Leave();

			// Throw an exception
			throw Exceptions::DuplicateSingleton();
		}
		Instance = static_cast <T*> (this);

		// Leave critical section
		CriticalSection.Leave();
	}

	~Singleton( )
	{
		// Enter critical section, modifys static objects
		CriticalSection.Enter();

		// Check that the singleton has been created
		if(Instance == NULL)
		{
			// Make sure the critical section is not orphoned
			CriticalSection.Leave();

			// Throw an exception
			throw Exceptions::InvalidSingleton();
		}
		Instance = NULL;

		// Leave critical section
		CriticalSection.Leave();
	}

	static T& GetSingleton()
	{
		// Enter critical section
		CriticalSection.Enter();

		// Check that the singleton is alive
		if(Instance == NULL)
		{
			// Make sure the critical section is not orphoned
			CriticalSection.Leave();

			// Throw an exception
			throw Exceptions::InvalidSingleton();
		}

		// Done here so that it is inside the critical section
		T& Result = *Instance;

		// Leave critical section
		CriticalSection.Leave();

		return Result;
	}

	static T* GetSingletonPtr()
	{
		// Enter critical section
		CriticalSection.Enter();

		// Done here so that it is inside the critical section
		T& Result = *Instance;

		// Leave critical section
		CriticalSection.Leave();

		return Instance;
	}
	
	static void Initialize()
	{
		new T();
	}
	static void CleanUp()
	{
		// Make sure that the singleton is alive
		if(GetSingletonPtr() == NULL)
		{
			// Throw an exception
			throw Exceptions::InvalidSingleton();
		}
		delete Instance;
	}
};

// Static initializing
template <class T> T* CJT::Singleton <T>::Instance = NULL;
template <class T> CCriticalSection CJT::Singleton <T>::CriticalSection();
Thanks. PS: The CCriticalSection class shown in there isn't the MFC one, a custom one based on WinAPI critical sections.

Share this post


Link to post
Share on other sites
Advertisement
The singleton-related functionality is synchronized. However, use RAII, especially for locks and critical sections.

Also, the object itself will not be synchronized, so you'll have to lock it anyway.

As for using singletons, if the system does flip out when you use several instances, then it's a good idea as long as you respect elementary guidelines (such as not accessing the singleton directly, except once per thread).

Share this post


Link to post
Share on other sites
Quote:
Original post by ganbree

Now I've written it and it works single-threaded, I've tried to synchronize it, however I'm not sure wether its completely thread-safe yet.


If singleton is mutable, it will always be single-threaded.

In addition, whatever getInstance() returns must be thread-safe. As end-result, since every call *must* be synchronized, singletons reduce multi-threaded application to single-threaded one + overhead of synchronization.

If it's immutable, it doesn't need synchronization at all.

For multi-threaded access it's customary to provide per-thread globals (no longer singletons, since multiple instances exist), and access them as such, without synchronization. TLS is a convenient way of implementing that.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
In addition, whatever getInstance() returns must be thread-safe. As end-result, since every call *must* be synchronized, singletons reduce multi-threaded application to single-threaded one + overhead of synchronization.


... if there are collisions. For instance, if you perform a 10ms access in each thread once per second, collisions have a 3% chance of occuring, meaning you will run as multi-threaded most of the time.

If any synchronized access to data caused single-threading, then we couldn't share data between threads, could we?

Share this post


Link to post
Share on other sites
Why can't you just use a normal class, make one instance, and pass that around? You probably won't need those instances in more than a few other classes anyways. Global mutable state becomes a pain, just saying...

Share this post


Link to post
Share on other sites
ToohrVyk - By RAII do you mean by having a CCriticalSectionOwnership class and using scope to leave it instead of manually? I can see how that is better than my current implementation, added to the TODO list.

Now my use of a task and thread pool system should also reduce collision.

I'm currently thinking about what happens when ::CleanUp() is called while a Object& is still hanging around... Im not sure whether I need to explicitly initialize and clean up to singleton. Maybe I should have some kinda lazy initialization?

Evil Steve and Antheus, thanks for the all the singletons are evil posts. Your superiority complexes are really working overdrive today.

If the system breaks if there are multiple copies of a class then I should instead throw an exception to make the situation recoverable and debuggable. In doing so I am creating dead objects by throwing in their constructor, by doing so I am already enforcing that there can only be one valid instance of an object. Having dead objects lying around is dangerous, therfore a singleton is needed.

Does anyone have any help with the implementation of a thread safe singleton?

Share this post


Link to post
Share on other sites
Quote:
Original post by ganbree
Evil Steve and Antheus, thanks for the all the singletons are evil posts. Your superiority complexes are really working overdrive today.
I'm simply pointing out that this is one of the problems with singletons. Singletons are really just globals in disguise.

As for a thread safe singleton, you just have to make sure that every member function of the singleton is synchronised with a critical section.

Share this post


Link to post
Share on other sites
Quote:
Evil Steve and Antheus, thanks for the all the singletons are evil posts. Your superiority complexes are really working overdrive today.
It can be argued that a singleton is an appropriate solution only when it would be an error for there to be multiple instances, and when global access is required. It can also be argued that there is no need for objects that handle such things as graphics, audio, and input to be global, and that in fact it would be better if they weren't.

As such, it doesn't seem unreasonable to suggest that singletons might not be the best solution to your problem, and to provide you with references that provide more information on the subject.

Share this post


Link to post
Share on other sites
Well I have three options to handle the inability to hold multiple graphics objects.

> Do nothing, have unobvious crashes providing no information and leaving the user unaware as to why the engine is crashing when they add the input object for the first time, (or so they think).

> Throw an exception in the constructor. So this is a singleton without global access.

> Use a singleton.

After a rethought I'm leaning towards number two, because I've forgotten why I thought I needed global access now. Might have been be something to do with the massive indirection chains I'm noticing in my code.

Share this post


Link to post
Share on other sites
So my new Singleton implementation isn't strictly a singleton, as it doesn't provide global access.

template &lt;class T&gt; class CJT::Singleton
{
private:
static bool Created;
static CCriticalSection CriticalSection;
public:
Singleton( void )
{
// Enter critical section, modifys static objects
CriticalSection.Enter();

// Check that the singleton hasn't already been created
if(! Created)
{
// Make sure the critical section is not orphoned
CriticalSection.Leave();

// Throw an exception
throw Exceptions::DuplicateSingleton();
}

// Leave critical section
CriticalSection.Leave();
}

~Singleton( )
{
// Enter critical section, modifys static objects
CriticalSection.Enter();

// Check that the singleton has been created
if( Created )
{
// Make sure the critical section is not orphoned
CriticalSection.Leave();

// Throw an exception
throw Exceptions::InvalidSingleton();
}

// Leave critical section
CriticalSection.Leave();
}
};


Thus the name is a little confusing, any ideas as to a better one? I've swapped to this mostly because I like RAII, and using the classic singleton stops me for using it.

Share this post


Link to post
Share on other sites
Singletons without global access are great for abstracting hardware. As for name... *shrug*. "PrivateSingleton"? BTW, your implementation there seems to have a couple of bugs... Created is accessed but never set, and the if-clauses in the constructor and the destructor seem to be switched.

Share this post


Link to post
Share on other sites
Why not just use static functionality, instead of making a class at all?

Share this post


Link to post
Share on other sites
Yeh, I noticed that, slightly embarrassing mistakes those. Got those fixed.

As to using a class instead of using statics, RAII and implicit destruction.

For naming it I've gone for "GlobalSingleton" for the classic singleton with global access and "LocalSingleton" for the half-singleton thing, fairly logical.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement