Serving the Quantitative Finance Community

 
User avatar
kevin08
Topic Author
Posts: 0
Joined: October 24th, 2008, 11:42 pm

C++: Portable Multithreaded Singleton

November 24th, 2009, 1:11 am

It uses boost thread library. Your critique is greatly appreciated.
Last edited by kevin08 on November 23rd, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

November 25th, 2009, 11:37 am

Ah yes, Singleton is the Holy Grail of patterns if you want to have a shot at it (the C++ committee gave up I believe) I would 1st of all not do the GOF OO Singleton (it's wrong paradigm and I bet it's not thread-safe) but Singleton<T>. have a zip file using a Destroyer and instead of that these days boost smart pointers are better.The problem with static objects is that they are created before main(). How will deadlock be detected and/or avoided? Another potential peformance problems: mutexes are expensive, especially in loops. Also, if the singleton is read-only then no mutex is needed.I have applied DP for some time now, but have never found a reason for using Singleton in many applications. I have found many reasons for _not_ using it. It is scary and time-consuming.I don't want to be a spoil sport but it is a non-trivial exercise. (BTW all static objects in .NET framework are thread-safe so application develolpers will need to do something similar).
Attachments
single.zip
(134.27 KiB) Downloaded 75 times
Last edited by Cuchulainn on November 24th, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
kevin08
Topic Author
Posts: 0
Joined: October 24th, 2008, 11:42 pm

C++: Portable Multithreaded Singleton

November 25th, 2009, 5:42 pm

Local static variables are initialized on first use. boost::call_once insures that the static instance is initialized only once without deadlock or race condition. boost::lock_guard insures that print() is unlocked even after an exception is thrown. The static local variables are properly destroyed when program exists, but client code can't access singleton's destructor. There is no need to use smart pointers. The singleton assumed to be non constant, so that synchronization is required. Is there faster alternative to mutex?I compiled it with msvc9 and mingw and it works (is seems).
Last edited by kevin08 on November 24th, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

November 28th, 2009, 4:04 pm

QuoteOriginally posted by: kevin08Local static variables are initialized on first use. boost::call_once insures that the static instance is initialized only once without deadlock or race condition. boost::lock_guard insures that print() is unlocked even after an exception is thrown. The static local variables are properly destroyed when program exists, but client code can't access singleton's destructor. There is no need to use smart pointers. The singleton assumed to be non constant, so that synchronization is required. Is there faster alternative to mutex?I compiled it with msvc9 and mingw and it works (is seems).In general, mutexes are bottlenecks. Since there is only one instance there is probably no performance difference between lock_guard and unique_guard? If mutex can be used across processes it is a bottleneck but in this case this should not be the issue. Every time you access the Singleton (even just for read) you put a lock on it?Some remarks from app dev viewpoint1. Satic objects remain in memory for the duration of the program. All the objects you need must be initialised before main()2. What if I have an app with n Singletons of different classes, n >=1? And what are the consequences?3. Did you gave a look at boost Flyweight? It might be a complementary solution to Singleton.4. C++ does not have a finalize() as such. I am wondering if the Singleton goes kapot (deadly embrace, exception) how can code be run to clean up resources? E.g. let's say an object has the lock and it breaks down. Who will then release the lock?5. How do propose to create Singletons of type X, Y and Z in an application?6. Do I have to worry about cache coherence and the static object? e.g. the Publisher-Subscriber? Hopefully it should be OK. But I don't know.7. At the end of the day, what's in a Singleton? In my experience, it tends to be just data.These are general questions. Having a real example will show how these points pan out. Mostly I use OpenMP and C# threads and some boost thread but the issues are the same in all languages. If you like to post the code(if it has changed from V1) and some test code I would give it a go to test it. Just wondering using OpenMP with boost Singleton?
Last edited by Cuchulainn on November 27th, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

November 28th, 2009, 6:49 pm

Regarding point 6 in my previous, this article is relevant, in particular volatile keyword. edit: In a slightly different context, OpenMP has the 'threadprivate' keyword to make a global variable private to each thread. This is important because of the different kinds of memory; So, we need to ensure that it is no stale data we are working with.
Last edited by Cuchulainn on November 28th, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
kevin08
Topic Author
Posts: 0
Joined: October 24th, 2008, 11:42 pm

C++: Portable Multithreaded Singleton

November 30th, 2009, 4:16 pm

Thanks for a good article. I see that my singleton isn't safe, because it uses Double-Checked Locking.As for point 1 not all static objects must be initialized before main(). Function locals initialized on first use.
 
User avatar
quantmeh
Posts: 0
Joined: April 6th, 2007, 1:39 pm

C++: Portable Multithreaded Singleton

November 30th, 2009, 5:11 pm

singleton is one pattern that can't be implemented in a practical way, unless you put a lot of constraints such as the application being local, i.e. not networked etc.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

November 30th, 2009, 8:11 pm

QuoteOriginally posted by: jawabeansingleton is one pattern that can't be implemented in a practical way, unless you put a lot of constraints such as the application being local, i.e. not networked etc.Yes, Singleton lives in 1 process. Otherwise, you will have to call the pattern something else. BTW, does the Singleton need to be persistent?
 
User avatar
quantmeh
Posts: 0
Joined: April 6th, 2007, 1:39 pm

C++: Portable Multithreaded Singleton

November 30th, 2009, 8:20 pm

QuoteOriginally posted by: CuchulainnBTW, does the Singleton need to be persistent?i think it's irrelevant.in fact, transactional database can be used to implement distributed singleton.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

November 30th, 2009, 8:50 pm

QuoteOriginally posted by: jawabeanQuoteOriginally posted by: CuchulainnBTW, does the Singleton need to be persistent?i think it's irrelevant.in fact, transactional database can be used to implement distributed singleton.I think you have just moved the goalposts. We are talking about shared memory, not distributed memory, yes? I include my original qualification, see QuoteYes, Singleton lives in 1 process. Otherwise, you will have to call the pattern something else. The scope is the GOF Singleton, not the 'something else', yes?
Last edited by Cuchulainn on November 29th, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
quantmeh
Posts: 0
Joined: April 6th, 2007, 1:39 pm

C++: Portable Multithreaded Singleton

December 2nd, 2009, 4:02 am

QuoteOriginally posted by: CuchulainnI think you have just moved the goalposts. We are talking about shared memory, not distributed memory, yes? I include my original qualification, see QuoteYes, Singleton lives in 1 process. Otherwise, you will have to call the pattern something else. The scope is the GOF Singleton, not the 'something else', yes?i'm not sure about it. i've been working on so called "enterprise apps". these things are deployed on clusters of app servers. theoretically any component on any server can access any resource in network. hence, calling something a singleton is misleading unless this guy has exactly one instance in the network. even when it's on the same server, there are multiple class-loader inside each VM. it's not easy to make a singleton even on one node in such environment.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

December 24th, 2009, 3:56 pm

kevin08,Here is a singleton in C#, could compare, it uses a mutex.Singleton
Last edited by Cuchulainn on December 23rd, 2009, 11:00 pm, edited 1 time in total.
 
User avatar
dobranszky
Posts: 0
Joined: January 8th, 2006, 11:53 am

C++: Portable Multithreaded Singleton

January 7th, 2010, 8:46 am

I made the following simple implementation of Singleton. I know that Double-Checked Locking (DPL) may fail in theory, but using a temp variable I have never experienced any problem (I use the Intel C++ compiler on Windows).I use the singleton pattern for my issue logger like Singleton<IssueLog>::Instance().Add<eDebug>(dataToLog); I change the verbosity level of my logger in runtime. If the verbosity level is not reached, thanks to DPL the logging code has basically no overheat. In general I log issues from OpenMP threads.I put px into the function. Therefore, I can forecast when my logger object is destructed. At the time of destruction I serialize the issues using Boost that has itself static variables initialized at the load of the DLL. Using scoped_ptr my logger is automatically destructed and the issues are serialized when I unload my DLL.An alternative could be to use non-thread-safe singletons and force them to instantiate the underlying object when the DLL is loaded. At that time there is usually only one thread active. Therefore, there is no need for a mutex or for DPL. An example for this can be found in boost/serialization/singleton.hpp. However, in this case in the constructor of the underlying object we have to reference all other static objects and singletons that we would like to destruct strictly after that the destruction of our underlying object has already finished. For instance, in my case in the constructor of IssueLog I have to reference the Boost Serialization singletons, otherwise I cannot serialize the issues when my IssueLog is destructed. Sometimes, it may be difficult to discover each dependence.
Last edited by dobranszky on January 7th, 2010, 11:00 pm, edited 1 time in total.
 
User avatar
Cuchulainn
Posts: 23029
Joined: July 16th, 2004, 7:38 am

C++: Portable Multithreaded Singleton

January 8th, 2010, 3:04 pm

QuoteOriginally posted by: dobranszkyI made the following simple implementation of Singleton. I know that Double-Checked Locking (DPL) may fail in theory, but using a temp variable I have never experienced any problem (I use the Intel C++ compiler on Windows).I use the singleton pattern for my issue logger like Singleton<IssueLog>::Instance().Add<eDebug>(dataToLog); I change the verbosity level of my logger in runtime. If the verbosity level is not reached, thanks to DPL the logging code has basically no overheat. In general I log issues from OpenMP threads.I put px into the function. Therefore, I can forecast when my logger object is destructed. At the time of destruction I serialize the issues using Boost that has itself static variables initialized at the load of the DLL. Using scoped_ptr my logger is automatically destructed and the issues are serialized when I unload my DLL.An alternative could be to use non-thread-safe singletons and force them to instantiate the underlying object when the DLL is loaded. At that time there is usually only one thread active. Therefore, there is no need for a mutex or for DPL. An example for this can be found in boost/serialization/singleton.hpp. However, in this case in the constructor of the underlying object we have to reference all other static objects and singletons that we would like to destruct strictly after that the destruction of our underlying object has already finished. For instance, in my case in the constructor of IssueLog I have to reference the Boost Serialization singletons, otherwise I cannot serialize the issues when my IssueLog is destructed. Sometimes, it may be difficult to discover each dependence.Is there a fundamental reason for using scoped pointers? A shared pointer is a better metaphor imo because multiple objects access it and it lives until no longer needed.QuoteFor instance, in my case in the constructor of IssueLog I have to reference the Boost Serialization singletons, otherwise I cannot serialize the issues when my IssueLog is destructed. Sometimes, it may be difficult to discover each dependence.A possible useful feature is that they have 'custom deleters' by using function objects so thar resource deallocation is controllled. It is called even when an exception occcurs.I am wondering if using boost::any would be better than template arguments...
Last edited by Cuchulainn on January 7th, 2010, 11:00 pm, edited 1 time in total.