Thread-safe singleton (was [FSM] Review library version update)

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrey Semashev
Hi Andrey,
Tuesday, February 6, 2007, 1:08:25 AM, you wrote:
Is there interest in having a boost singleton? A preliminary implementation of it could use boost::once. Then all lazy initializations would happen through that interface.
Just a thought.
I think a generic implementation of a thread-safe singleton is a nice idea. I encounter this problem quite often. Although, once-based implementation doesn't suit me very well in this case.
What kind of solutions have you come up with for lazily initializing singletons in a thread-safe manner? What are your reasons for not preferring a boost::once implementation? I can only think of boost::once based or platform specific, which scares me, to be frank! The solution to the problem seems to be a function of hardware and OS primitives which (I thought) pthread_once/family solve as nicely as you'd want. Personally, I'm fairly new to the whole multi-proc scene so I'd really appreciate some enlightenment! Sohail

Hello Sohail, Tuesday, February 6, 2007, 1:34:50 AM, you wrote:
Hi Andrey,
Tuesday, February 6, 2007, 1:08:25 AM, you wrote:
Is there interest in having a boost singleton? A preliminary implementation of it could use boost::once. Then all lazy initializations would happen through that interface.
Just a thought.
I think a generic implementation of a thread-safe singleton is a nice idea. I encounter this problem quite often. Although, once-based implementation doesn't suit me very well in this case.
What kind of solutions have you come up with for lazily initializing singletons in a thread-safe manner?
In most cases I tried not to create the singleton lazily but initialize it as soon as possible. The perfect time is on executable module load which, AFAIK, is always done in single thread on platforms I have faced yet. Such approach was quite sufficient for me since it solves the key problem of the singleton creation. And the created singleton may be not fully initialized at first, i.e. it may not acquire significant system resources on construction but may do so on first requests to it. Such requests are easy to synchronize since the singleton with a mutex already exists. Maybe a similar approach in a generic implementation of a lazy singleton worth considering too. I mean, on module load the implementation may safely construct a mutex and a null reference to a yet non-exiting singleton instance (see Alexandrescu's implementation with dead reference detection). This would let you to synchronize later when the instance is requested first time and needs to be created. And the very same mutex may be used by the singleton later for its own needs. The problem is that I guess not every compiler/platform would let you to hook into the module load sequence. For those configurations we might fall back to once-based implementation.
What are your reasons for not preferring a boost::once implementation? I can only think of boost::once based or platform specific, which scares me, to be frank!
In the Boost.FSM lib boost::call_once is not very desirable because that lib is intended to be light. It may even be used without threading at all (and in fact, this is expected to be the major domain of use). So I cannot force users to build Boost.Thread just to support the internals of the header-only library. The same disadvantage would be in case of the generic singleton implementation. I believe that such implementation should provide a way to create singletons without requiring building any libraries in single-thread and even in multi-thread environment, where possible. Maybe if there was some lightweght_call_once somewhere in Boost the problem would be solved.
The solution to the problem seems to be a function of hardware and OS primitives which (I thought) pthread_once/family solve as nicely as you'd want.
Pthreads are quite widespread but not ultimate. At least win32 threading needs to be supported too.
Personally, I'm fairly new to the whole multi-proc scene so I'd really appreciate some enlightenment!
I'm no expert too. Let's hope that someone who really knows the field is reading this. -- Best regards, Andrey mailto:andysem@mail.ru

On Tuesday, February 06, 2007 8:09 PM, Andrey Semashev wrote:
Tuesday, February 6, 2007, 1:34:50 AM, you wrote:
...
What kind of solutions have you come up with for lazily initializing singletons in a thread-safe manner?
In most cases I tried not to create the singleton lazily but initialize it as soon as possible. The perfect time is on executable module load which, AFAIK, is always done in single thread on platforms I have faced yet. Such approach was quite sufficient for me since it solves the key problem of the singleton creation.
I don't see how such an assumption can be made. What if a thread is started in the constructor or initializer of a global object? I.e.: void thread_func() { // This may be called before, or concurrently with, // your singleton early-initialization function singleton::instance()->do_something(); } class foo { foo() { boost::thread my_thread (&thread_func); } }; // Constructed on module load foo global_foo; Then there's the issue of singletons located in shared libraries (on *nix platforms) or DLL's (on Windows). If these modules are loaded dynamically, there may already be multiple threads running. Moshe

Hello Moshe, Thursday, February 8, 2007, 12:42:26 PM, you wrote:
On Tuesday, February 06, 2007 8:09 PM, Andrey Semashev wrote:
Tuesday, February 6, 2007, 1:34:50 AM, you wrote:
...
What kind of solutions have you come up with for lazily initializing singletons in a thread-safe manner?
In most cases I tried not to create the singleton lazily but initialize it as soon as possible. The perfect time is on executable module load which, AFAIK, is always done in single thread on platforms I have faced yet. Such approach was quite sufficient for me since it solves the key problem of the singleton creation.
I don't see how such an assumption can be made. What if a thread is started in the constructor or initializer of a global object? I.e.:
[snip] Yes, theoretically it is possible. I guess, I've never met the code that spawns a thread during module loading process. I have to admit though that such code is not safe itself (with no regard to the singleton issue). The thread spawns at the moment when global initialization is not finished and it cannot catch the moment when it is. This means that it may not safely access any global data in the first place, including the singleton. So if such code is written, the developer should have beared in mind that the thread should be isolated at least until the initialization is completed. And the main thread can tell the spawned thread when it is completed, which may be done after the singleton construction, of course. So, I agree that it is possible. But if the developer is not foe to himself, he should have taken necessary precautions.
Then there's the issue of singletons located in shared libraries (on *nix platforms) or DLL's (on Windows). If these modules are loaded dynamically, there may already be multiple threads running.
The library loading process is usually made though OS API which synchronizes internally. That makes library initialization thread-safe, unless it spawns a thread as you noted above. -- Best regards, Andrey mailto:andysem@mail.ru
participants (3)
-
Andrey Semashev
-
Moshe Matitya
-
Sohail Somani