Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

How to make this class a Singleton?

Posted on 2010-09-10
11
Medium Priority
?
612 Views
Last Modified: 2013-11-11
Hey Experts.
I need to get the class ServerDispatcher a singleton but I really don't know how.  I'm on a Linux platform. I've read a couple of things about singletons over the net but the subjetct is kinda cloudy for me. If u can show me how the code below can be turned into a singleton and how access to its functions will be, it will be great. Also, if it is possible, explain to me how singletons work. Nothing too complex or big, I don't want to take a whole lot of your time with this.

Thanks in advance.
The code to the class is here:
ServerDispatcher.h
#ifndef SERVERDISPATCHER_H
#define SERVERDISPATCHER_H

#include "ClientHandler.h"
#include <string>
#include <deque>
#include <list>
#include <pthread.h>

class ServerDispatcher
{
public:
   ServerDispatcher( );
   virtual ~ServerDispatcher( );

   void AddClient( ClientHandler *aClientHandler );
   void DeleteClient( ClientHandler *aClientHandler );
   void DispatchMessage( std::string message );
   bool IsClientListEmpty( );
   void run( );

private:
   std::deque< std::string > m_ServerMessageQueue;
   std::list< ClientHandler* > m_Clients;
   pthread_mutex_t m_mutex;
   pthread_t m_thread;

   std::string GetMessageFromQueue( );
   void SendMessageToAllClients( std::string message );
   static void * StartThread( void *arg );
};

#endif // SERVERDISPATCHER_H

Open in new window


ServerDispatcher.cpp
#include "ServerDispatcher.h"
#include "ClientHandler.h"
#include <string>
#include <deque>
#include <list>
#include <exception>
#include <iostream>
#include <pthread.h>

ServerDispatcher::ServerDispatcher( )
{
   pthread_create(&m_thread, 0, &ServerDispatcher::StartThread, this);
   pthread_mutex_init( &m_mutex, NULL );
}

ServerDispatcher::~ServerDispatcher( )
{
   pthread_mutex_destroy( &m_mutex );
}

//Add ClientHandler to the list
void ServerDispatcher::AddClient( ClientHandler *aClientHandler )
{
   m_Clients.push_back( aClientHandler );
}

//Delete ClientHandler from list
void ServerDispatcher::DeleteClient( ClientHandler *aClientHandler )
{
   m_Clients.remove( aClientHandler );
   delete aClientHandler;
}

//Add message to the ServerMessageQueue deque
void ServerDispatcher::DispatchMessage( std::string message )
{
   pthread_mutex_lock(&m_mutex);
   m_ServerMessageQueue.push_front( message );
   pthread_mutex_unlock(&m_mutex);
}

//Get next message from ServerMessageQueue deque and delete it
std::string ServerDispatcher::GetMessageFromQueue( )
{
   while ( true )
   {
      if ( m_ServerMessageQueue.size( ) != 0 )
      {
         break;
      }
   }

   pthread_mutex_lock(&m_mutex);
   std::string message = m_ServerMessageQueue.back( );
   m_ServerMessageQueue.pop_back( );
   pthread_mutex_unlock(&m_mutex);

   return message;
}

//Send message to the ClientMessageQueue of all clients in the list
void ServerDispatcher::SendMessageToAllClients( std::string message )
{
   std::list< ClientHandler* >::iterator it;

   for ( it = m_Clients.begin( ); it != m_Clients.end( ); it++ )
   {
      ClientHandler* clientHandler = *it;
      clientHandler->SendMessage ( message );
   }
}

bool ServerDispatcher::IsClientListEmpty( )
{
   if ( m_Clients.empty( ) )
   {
      return true;
   }
   else
   {
      return false;
   }
}

//Keep getting messages from the ServerMessageQueue and sending them to all the clients
void ServerDispatcher::run( )
{
   while ( true )
   {
      try
      {
      std::string message = GetMessageFromQueue( );
      SendMessageToAllClients( message );
      }
      catch ( std::exception &e )
      {
         std::cerr << "Error while sending message to all clients." << std::endl;
         break;
      }
   }
}

void * ServerDispatcher::StartThread( void *arg )
{
   reinterpret_cast<ServerDispatcher *>(arg)->run( );
}

Open in new window

0
Comment
Question by:PDamasceno
  • 6
  • 5
11 Comments
 
LVL 40

Accepted Solution

by:
evilrix earned 2000 total points
ID: 33645622
Meyer's Singleton is the simplest way to do this.
http://www.devarticles.com/c/a/Cplusplus/C-plus-plus-In-Theory-The-Singleton-Pattern-Part-I/4/
// Note the first (and only the first) call is not thread safe. Call it one from main first to construct singleton if using threads.

ServerDispatcher & GetSingleton()
{
   static ServerDispatcher sd;
   return sd;
}

ServerDispatcher & sd = GetSingleton();

Open in new window

0
 

Author Comment

by:PDamasceno
ID: 33645802
One thing that keep bugging me.
I will have to change only the header of the class?
Also by thread safe you mean what? The ServerDispatcher class is a thread being run from another class in my program. It is possible to make the ServerDispatcher a threaded singleton class? If it is possible, I need to create an object of ServerDispatcher in that other class?
0
 

Author Comment

by:PDamasceno
ID: 33645816
Here's where the ServerDispatcher object is created.
Server.cpp
[code]
int main( )
{
   ServerDispatcher serverDispatcher; //Here is where the object is created.

   Socket serverSocket;
   serverSocket.Listen( port );

[/code]
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 40

Expert Comment

by:evilrix
ID: 33645845
>> I will have to change only the header of the class?
You don't need to make *any* changes to the class. Just provide the function shown above.

>> Also by thread safe you mean what?
The very first time this function is call it creates the singleton. If you try and call it using multiple threads at that point you will get a race condition. This is trivial to fix - just call the function one BEFORE you spawn any threads. Once the initial call is complete the singleton is constructed and subsequent calls are thread safe.

>>  The ServerDispatcher class is a thread being run from another class in my program
That's perfectly fine, it's only if you try to call the function GetSingleton() from multiple threads before it's been called once from a single thread that there is an issue.

>>  It is possible to make the ServerDispatcher a threaded singleton class?
What do you mean? A singleton is a singleton!

>>  If it is possible, I need to create an object of ServerDispatcher in that other class?
The GetSingleton() function can be a [static] class member

0
 
LVL 40

Assisted Solution

by:evilrix
evilrix earned 2000 total points
ID: 33645886
>> Here's where the ServerDispatcher object is created.

How is that accessed from other code?

With the Meyer's singleton pattern you would have

Server.cpp
[code]
int main( )
{
   ServerDispatcher & serverDispatcher =  GetSingleton(); //Here is where the object is created.

   Socket serverSocket;
   serverSocket.Listen( port );

[/code]

Note, that GetSingleton() can be call from anywhere that the function is visible so it doesn't need to be assigned in main (although calling it here will ensure it is fully constructed before you spawn threads). In other words, anywhere you need access to the singleton just call GetSingleton().

Also note that singletons make code harder to test and maintain. A singleton is analogous to a global variable warts and all!
0
 
LVL 40

Expert Comment

by:evilrix
ID: 33645913
> anywhere you need access to the singleton just call GetSingleton().

The will all use the same instance, the one that is statically bound in the GetSingleton() function. I presumed you understand how function static variables work. "When you declare a variable in a function, the static keyword specifies that the variable retains its state between calls to that function."
0
 

Author Comment

by:PDamasceno
ID: 33646013
Ok. Things are clearer now.
The ServerDispatcher class is acessed by multiple ClientHandler threads. What the ClientHandler threads do is just call DispatchMessage function from ServerDispatcher to add a message to the queue.
So for the last questions I hope.
How the functions from ServerDispatcher are called using this singleton implementation?
I presume I will have to use mutex to lock and unlock the access of the ClientHandler threads right?
0
 
LVL 40

Assisted Solution

by:evilrix
evilrix earned 2000 total points
ID: 33646262
>> The ServerDispatcher class is acessed by multiple ClientHandler threads.
That's perfectly fine, just make sure you call GetSingleton() in main before you spawn any threads just to make sure the singleton is fully constructed. After this the call to GetSingleton() is completely thread safe.

>> I presume I will have to use mutex to lock and unlock the access of the ClientHandler threads right?
Access to the object via the GetSingleton() function is thread safe but that doesn't mean ServerDispatcher will be - you will still need to provide proper thread safety in the class itself!

>> How the functions from ServerDispatcher are called using this singleton implementation?

GetSingleton().Function();

or

ServerDispatcher & sd = GetSingleton();
sd.Function();

One more thing...

To make sure you don't accidentally do this...

ServerDispatcher sd = GetSingleton(); // Oops, should be a reference assignment

Make sure you declare but don't implement a copy constructor and assignment operator for ServerDispatcher  but don't implement them. Then, if you accidentally try to do an assignment by value the compiler will generate a compile time error. This is known as implementing noncopyable semantics.

http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-copyable_Mixin
0
 

Author Comment

by:PDamasceno
ID: 33646264
I'm also getting this error when I try to compile Server.cpp with the new code:
Server.cpp:21: error: 'GetSingleton' was not declared in this scope
0
 

Author Comment

by:PDamasceno
ID: 33646654
Everything working fine now.
Thanks evilrix.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 33646857
>> Everything working fine now.

Cool, I presume the above error was because you hadn't declared GetSingleton() ??
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction A frequently used term in Object-Oriented design is "SOLID" which is a mnemonic acronym that covers five principles of OO design.  These principles do not stand alone; there is interplay among them.  And they are not laws, merely princ…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

916 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question