
Jason Hise wrote:
I'm actually working on the longevity policy now. I'm trying to do it without using atexit, and instead using a hidden internal singleton that manages the lifetimes of the others. It should be interesting.
Good idea - I look forward to seeing the results.
3) Possibly include the ability to turn off phoenix singletons in the dependency lifetime policy.
From what I remember, Loki throws an exception.
This leads to an interesting question: what should happen if a class tries to get access to a destroyed singleton? I would personally think that it would always be desirable to have it come back, but then this is just my opinion and probably falls into the same category as me preferring dependencies to longevities. Which leads me to wonder if OnDeadReference should be an additional policy of the lifetime policy itself.
Let me give you an example where you may want a dead reference exception rather than a phoenix singleton. Let's say you have a singleton that performs a client access to a database. When the client is started up, it asks for a username and password, and logs the client access in the database. You definitely would not want this to go through a phoenix singleton because of the side-affects. Making OnDeadReference a policy of the lifetime policy probably makes a lot of sense, since you have essentially implemented the phoenix singleton as an extra to the lifetime policy in the dependency model.
4) Threading.
I'm going to need help with this one. My current thought is to provide a lock policy. The lock would be required to provide locking upon creation and unlocking upon destruction, and then all the other policies of the singleton would inherit this policy and could simply insert lock objects wherever they are needed. The default single threaded lock would just be an empty class. Unfortunately I have no experience with how threading actually works, and I am worried that the two threads would just end up creating two different locks and neither would block the other. If I am not on the right track, please point me in the right direction.
The problem with threading is that it is up to the OS to define the threading system. This means that threading is usually non-portable. I would recommend therefore looking at boost.threads which provides a portable threading system. Loki uses a very simple system of policies. The 3 policies implemented are a SingleThreadPolicy, ObjectLevelLocking and ClassLevelLocking. The object level locking basically locks a mutex that is defined on an object level, whereas the class level locks a mutex for all objects of that class. The implementation is via CRTP again. There are some added bits in Loki like the volatile type is typedefed so you can get the volatile qualifier right (you shouldn't use volatile in single-threaded because it can disable compiler optimisations). It does this using template <class Host> class ObjectLevelLocking { typedef volatile Host VolatileType; }; whereas the SingleThreaded version just does: typedef Host VolatileType; The locking itself works with an inner class called Lock that you construct on the stack whenever you need to lock. On construction it locks the mutex and on destruction it frees it. I've not personally used the boost threads library so I can't help you on that one. Dave Handley

Dave Handley wrote:
Let me give you an example where you may want a dead reference exception rather than a phoenix singleton. Let's say you have a singleton that performs a client access to a database. When the client is started up, it asks for a username and password, and logs the client access in the database. You definitely would not want this to go through a phoenix singleton because of the side-affects. Making OnDeadReference a policy of the lifetime policy probably makes a lot of sense, since you have essentially implemented the phoenix singleton as an extra to the lifetime policy in the dependency model.
Alrighty, I'll start work on splitting that off into its own GetInst policy.
The problem with threading is that it is up to the OS to define the threading system. This means that threading is usually non-portable.
I don't think it is necessary for the library itself to be multi-threaded. I think it just needs to have a hook that allows client code to make it thread safe. The interface for such a hook would be the only thing provided (the default single threaded policy defining all the usable methods and leaving them all blank), and the client could then implement an OS specific thread safety policy and pass it in. A dependency on a whole threading library doesn't seem like a good idea for something that only some clients might want. -Jason

"Jason Hise" wrote: [snip]
I don't think it is necessary for the library itself to be multi-threaded. I think it just needs to have a hook that allows client code to make it thread safe. The interface for such a hook would be the only thing provided (the default single threaded policy defining all the usable methods and leaving them all blank), and the client could then implement an OS specific thread safety policy and pass it in. A dependency on a whole threading library doesn't seem like a good idea for something that only some clients might want.
Maybe it could have threading policy, defaulting to the same mechanism shared_ptr uses, other options being no-locking and user-locking. /Pavel

On Wed, 12 Jan 2005 01:37:15 +0100 "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote:
Maybe it could have threading policy, defaulting to the same mechanism shared_ptr uses, other options being no-locking and user-locking.
Umm... not trying to start a war or anything, but please do not do that. Personally, I do not like the threading policy of shared_ptr. I use it, but I really do not like it. In general, the Boost preference seems to be compiled code is either multithread enabled or not (i.e., object are different sizes based on compile time macros). In my experience, I have found making the thread policy an actual policy (similar to how ACE does it) better. It allows me to compile/link different policies, depending on how they are used. For example, if I have a multi-threaded application, Boost classes require me to use all multithreaded support. However, my main thread may be tight, and use shared_ptr objects that do not span multiple threads. In that case, I'd like to use something like shared_ptr< Foo, Noop_Lock_Policy > for stuff I know is OK without locking...

Jody Hagins wrote:
For example, if I have a multi-threaded application, Boost classes require me to use all multithreaded support. However, my main thread may be tight, and use shared_ptr objects that do not span multiple threads. In that case, I'd like to use something like shared_ptr< Foo, Noop_Lock_Policy > for stuff I know is OK without locking...
I have to agree with this. I've often wondered about something that lives between a boost::scoped_* and a boost::shared_* along the lines of what you suggest. Ideally I'd like something that can be promoted to full shared status (reference counted and locking) at the thread boundaries. But this could be dangerous obviously. I certainly think a single threaded reference counted shared_* object would be useful even within a multi threaded application if you know you have single thread ownership. For example, in a pipelined (1 thread per stage) process I'm passing Data Transfer Objects along, which contain shared_ptr/shared_array members that originally come from a aloocated 'pool' of resources (memory buffers for instance). Once I'm inside a stage of my pipeline "I'm" the owner so I don't need the locking, anymore. Do others think this is sane? Kevin -- | Kevin Wheatley, Cinesite (Europe) Ltd | Nobody thinks this | | Senior Technology | My employer for certain | | And Network Systems Architect | Not even myself |

It would be really nice if "TR2" would provide enum thread_safety { unsafe, basic }; // strong aside for a moment template<typename numeric, thread_safety scheme_thread_safety> class refcount; (or something like that) and also provide "thread-unsafe" shared_ptr in addition to the current one with its "basic" thread-safety. http://groups.google.de/groups?selm=3F1F26CC.4125AE8B%40web.de Note that in the case of immutable managed objects, "use_count_. decrement()" can be replaced by msync::none version (decrement() is a shortcut for decrement(msync::acq, msync::rel) but increments are all "naked"). Msync on self_count_ can be relaxed a bit as well. This can make quite a difference in performance. (E.g. on the upcoming Xbox... PS3 aside for a moment ;-) ) regards, alexander.

On 01/12/2005 08:03 AM, Alexander Terekhov wrote: [snip]
Note that in the case of immutable managed objects, "use_count_. decrement()" can be replaced by msync::none version (decrement() is a shortcut for decrement(msync::acq, msync::rel) but increments are all "naked"). Msync on self_count_ can be relaxed a bit as well. This can make quite a difference in performance.
I'm a thread novice, so forgive me if this is dumb question, but why are increments "naked" and what does "naked" mean? One reason I'm interested is that IIUC, weighted reference counting doesn't require any synchonization on increments, but does require them on decrements. See the [lins*] references on: http://www.cs.kent.ac.uk/people/staff/rej/gcbib/gcbibL.html Thus, wouldn't weighted refcounts also make quite a difference in performance? However, the cost for the weights is 1 refcount for each smart pointer, or something like that.

Larry Evans wrote: [...]
why are increments "naked"
Because additional constrains imposed on compiler and/or hardware with respect to reordering across increments would serve no purpose for the intended use of that smart pointer.
and what does "naked" mean?
Naked means "no barrier". BTW, for mutable objects with trivial destructors, use_count_ decrements do need classic msync::rel (release) but don't need classic msync::acq (when the count drops to min/zero), only cchsb (control condition hoist store barrier) and only if you can write something to the storage of the dead object (reuse it). A sorta pseudo C++ illustration of cchsb can be found here: http://www.google.de/groups?threadm=418AAF67.99C5F579%40web.de See also http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf I mean section 4.1. In mutex_and_condvar_free_single_producer_single_consumer case, "speculative" (hoisted above control condition) store doesn't need any correction (let's treat usleep() as no-throw ;-) ). regards, alexander.

Pavel Vozenilek wrote:
Maybe it could have threading policy, defaulting to the same mechanism shared_ptr uses, other options being no-locking and user-locking.
To mirror another message I sent regarding aligned_storage, I like the idea of making this library a part of boost, but I don't like the idea of having countless dependencies upon boost. Because a singleton doesn't do any multi threading itself, it shouldn't rely on a full fledged threading library at all. The only thing really necessary is to make the singleton library thread safe when used in the context of multiple threads. I would think this would be as simple as passing in a class which can be used as a mutex, locking upon creation and unlocking upon destruction. If there are further safety issues of which I am unaware, I think it does make sense to provide *the interface* for them in a single-threaded safety policy (leaving empty definitions). Any commonly used thread safety policies that require a specific major threading library (like boost's) could be provided in a separate header. The main thing that I would like to know is what this thread safety *interface* should look like, if it should provide any features other than locking, and/or how specifically it should be used within the singleton itself (aka what operations need to be locked). -Jason

Jason Hise wrote: [...]
header. The main thing that I would like to know is what this thread safety *interface* should look like, if it should provide any features other than locking, and/or how specifically it should be used within the singleton itself (aka what operations need to be locked).
Nothing at all if the singleton itself is immutable or "atomic<>"-ized internally (lock-free). In this case, for thread-safe lazy init and static storage duration, the best "interface" is a synchronized static local. Some compilers* turn all static locals into synchronized static locals. (In MT mode. Same policy thing as with boost::shared_ptr. ;-) ) regards, alexander. *) E.g. see http://www.codesourcery.com/cxx-abi/abi.html#once-ctor

Alexander Terekhov wrote:
Jason Hise wrote: [...]
header. The main thing that I would like to know is what this thread safety *interface* should look like, if it should provide any features other than locking, and/or how specifically it should be used within the singleton itself (aka what operations need to be locked).
Nothing at all if the singleton itself is immutable or "atomic<>"-ized internally (lock-free). In this case, for thread-safe lazy init and static storage duration, the best "interface" is a synchronized static local. Some compilers* turn all static locals into synchronized static locals. (In MT mode. Same policy thing as with boost::shared_ptr. ;-) )
Please elaborate. I have very little threading background. What exactly is a synchronized static local? Is this a class or object level mutex, or something entirely different? The "some compilers" part worries me a bit, as I would like this library to be portable. When you refer to atomic<>, I presume you are referring to operations that are indivisible at the processor level. Are there such operations that can be assumed to be atomic on every processor, or would I be using a large boost library that defines common atomic operations based on the compiler, processor, and operating system? Thanks in advance. -Jason

Jason Hise wrote: [...]
Please elaborate. I have very little threading background. What exactly is a synchronized static local? Is this a class or object level mutex, or something entirely different?
It is a C++ incarnation of ages-old pthread_once(), so to say. For details, see: http://www.google.de/groups?selm=3EBB8DDC.C81DF4AE%40web.de http://www.google.de/groups?selm=41496597.F54DD01A%40web.de
The "some compilers" part worries me a bit, as I would like this library to be portable.
Yeah.
When you refer to atomic<>, I presume you are referring to operations that are indivisible at the processor level. Are there such operations that can be assumed to be atomic on every processor,
Atomicity is only one aspect. The rest is MT memory model with explicit reordering constraints coupled with atomic<> operations and a few bidirectional fences.
or would I be using a large boost library that defines common atomic operations based on the compiler, processor, and operating system?
Read this thread: http://www.google.de/groups?threadm=41E3B870.CA6DDE9D%40web.de regards, alexander.

To mirror another message I sent regarding aligned_storage, I like the idea of making this library a part of boost, but I don't like the idea of having countless dependencies upon boost.
Just going to jump out from lurk mode for a second here, hope you don't mind me butting in;) I really don't get what the problem with dependencies on boost is. The whole point of boost as I see it is a big repository of well developed and proven portable code, subverting this just brings all the associated maintenence problems of having effectively duplicated code. If someone installs the boost libraries they have no problems with dependencies as they have all the applicable code. If you want fine grained control for people who really do not want / have space for additional boost libraries being linked in then specifying a preprocessor directive at build time would seem appropriate. I would expect a boost library to support the other boost libraries as well out of the box if natural to do so, I would not like at all having to write extra code to get a multi-thread safe singleton. I don't know about gcc but I do know the vc dead code optimiser is very good and aggressive (far too much so under certain circumstances, just to check at the end is a small test) so linking to a library where most code is unused just doesn't bother me, maybe someone else can say how good gcc and metrowerks are in this respect. And anyway whats few k between friends these days for good solid and reliable code;) Maybe I'm missing some other reason to avoid the dependancy? Anyhow just my 2 aussie cents, thanks for the work your putting in, I would love to see this enter boost. cheers martin ------------------------------------------------------------------ Code is at bottom, the difference with vc is only 12k from a 923k library on disk using the boost policy and nothing at all if the policy isn't used but the library is still linked. It just doesn't seem worth putting any effort into avoiding boost (threads at least) if executable size is a problem. Results -------- (vc7.1) thread lib size : 923kb no boost at all : 76kb boost policy defined but not used : 76kb boost policy defined and used : 88kb (mingw-1.32.0rc1 - gcc 3.4.2) thread lib size : 335kb no boost at all : 474,875kb boost policy defined but not used : 474,875kb boost policy defined and used : 527,569kb ------------------------------------------------------------------- #define BOOST_LIB_DIAGNOSTIC #define USE_BOOST #define DEFINE_BOOST_BUT_DONT_USE #include <iostream> #ifdef USE_BOOST #include <boost/thread/mutex.hpp> #endif template<class LockType, class LockerType> struct LockerTraits { typedef LockType Lock; typedef LockerType Locker; }; struct NullLocker { NullLocker(int) {} }; typedef LockerTraits<int, NullLocker> NullLockPolicy; #if defined(USE_BOOST) && !defined(DEFINE_BOOST_BUT_DONT_USE) typedef LockerTraits<boost::mutex, boost::mutex::scoped_lock> BoostLockPolicy; #endif template<class Locker> struct Fish { void print() { typename Locker::Locker lock(m_lock); std::cout << "hello" << std::endl; } typename Locker::Lock m_lock; }; int main(int argc, char* argv[]) { #if defined(USE_BOOST) && !defined(DEFINE_BOOST_BUT_DONT_USE) Fish<BoostLockPolicy> fishy; #else Fish<NullLockPolicy> fishy; #endif fishy.print(); return 0; }

Martin Slater wrote:
Just going to jump out from lurk mode for a second here, hope you don't mind me butting in;) I really don't get what the problem with dependencies on boost is. The whole point of boost as I see it is a big repository of well developed and proven portable code, subverting this just brings all the associated maintenence problems of having effectively duplicated code.
I'm another lurker who agrees with this.

Deane Yang wrote:
Martin Slater wrote:
Just going to jump out from lurk mode for a second here, hope you don't mind me butting in;) I really don't get what the problem with dependencies on boost is. The whole point of boost as I see it is a big repository of well developed and proven portable code, subverting this just brings all the associated maintenence problems of having effectively duplicated code.
I'm another lurker who agrees with this.
Alright, I will agree that I should use boost if my library naturally requires it. The difficulty I am having is that only one special policy in my library requires it, not the singleton framework itself. I just want to split apart these dependencies. You know, the whole "only pay for what you use" thing. It seems like the most natural way to do this would be to just put this policy and any others that required boost in a separate header, like "boost_singleton_extensions.h" -Jason

dependencies. You know, the whole "only pay for what you use" thing. It seems like the most natural way to do this would be to just put this policy and any others that required boost in a separate header, like "boost_singleton_extensions.h"
Sounds good. cheers martin

Jason Hise wrote:
Deane Yang wrote:
Martin Slater wrote:
Just going to jump out from lurk mode for a second here, hope you don't mind me butting in;) I really don't get what the problem with dependencies on boost is. The whole point of boost as I see it is a big repository of well developed and proven portable code, subverting this just brings all the associated maintenence problems of having effectively duplicated code.
I'm another lurker who agrees with this.
Alright, I will agree that I should use boost if my library naturally requires it. The difficulty I am having is that only one special policy in my library requires it, not the singleton framework itself. I just want to split apart these dependencies. You know, the whole "only pay for what you use" thing. It seems like the most natural way to do this would be to just put this policy and any others that required boost in a separate header, like "boost_singleton_extensions.h"
Header separation shouldn't be done based on implementation details. Put every component of your library in a separate header and then there's no question which should be included to use a particular feature, and you don't have to move things around if your boost dependencies change. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Header separation shouldn't be done based on implementation details. Put every component of your library in a separate header and then there's no question which should be included to use a particular feature, and you don't have to move things around if your boost dependencies change.
You're right, that makes sense. I can do that. -Jason
participants (10)
-
Alexander Terekhov
-
Dave Handley
-
David Abrahams
-
Deane Yang
-
Jason Hise
-
Jody Hagins
-
Kevin Wheatley
-
Larry Evans
-
Martin Slater
-
Pavel Vozenilek