From: DeMarcus on
Joshua Maurice wrote:
> On Mar 15, 9:28 pm, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
>> Hi,
>>
>> I try to implement a simplified version of Alexandrescu's
>> Loki::SingletonHolder. Seehttp://loki-lib.sourceforge.net/html/a00670.html
>> row 717.
>>
>> My code looks like this.
>>
>> [...]
>>
>> What am I doing wrong?
>
> Well, for starters, why are you using the volatile keyword? Do you
> think it's a portable threading construct? It's not. volatile in C and
> C++ has nothing to do with threading. The C and C++ standards do not
> talk about threads, so anything they say about volatile is irrelevant.
> By POSIX, volatile means nothing special for threading. (The Microsoft
> compiler under certain versions does claim to make it like a mutex
> acquire and release, but let's just ignore this bad form for now. Use
> boost or ACE or some portable library if you need atomic functions, or
> wait for the new C++ standard. At worst, wrap volatile yourself to not
> litter your code with a not portable construct + usage.)
>

This makes me very confused. I've always been taught to use the volatile
keyword in front of variables that can be accessed from several threads.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: DeMarcus on
Johannes Schaub (litb) wrote:
> DeMarcus wrote:
>
>> Hi,
>>
>> I try to implement a simplified version of Alexandrescu's
>> Loki::SingletonHolder. See
>> http://loki-lib.sourceforge.net/html/a00670.html
>> row 717.
>>
>> My code looks like this.
>>
>> template<typename T>
>> class Singleton
>> {
>> public:
>> static T& getInstance()
>> {
>> return *instance_;
>> }
>>
>> private:
>> typedef volatile T* SPtr;
>> static SPtr instance_;
>> };
>>
>> template<typename T>
>> typename Singleton<T>::SPtr Singleton<T>::instance_;
>>
>> int main()
>> {
>> typedef Singleton<int> S;
>> S::getInstance() = 4711;
>> }
>>
>> But when I compile it with gcc 4.4.1 I get the following error message
>> at 'return *instance_;'.
>> "error: invalid initialization of reference of type 'int&' from
>> expression of type 'volatile int' "
>>
>> What am I doing wrong?
>>
>>
>
> "T&" designates the type "int&" , but "*instance" is an expression of type
> "volatile int". You cannot refer to a volatile object by a non-volatile
> expression. If you do nontheless by casting away volatile, behavior is
> undefined. The compiler guards you from that by not allowing the non-
> volatile reference to bind to expressions of volatile type.
>
> I dunno what Alexandrescu's code is doing, but surely there are more levels
> of indirections in his code that care for health :)
>

That's the thing! I do the same as him. This is what he does.

Here's Singleton.h

00717 template
00718 <
00719 typename T,
00720 template <class> class CreationPolicy = CreateUsingNew,
00721 template <class> class LifetimePolicy = DefaultLifetime,
00722 template <class, class> class ThreadingModel =
00722b LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
00723 class MutexPolicy = LOKI_DEFAULT_MUTEX
00724 >
00725 class SingletonHolder
00726 {
00727 public:
00728
00730 typedef T ObjectType;
00731
00733 static T& Instance();
00734
00735 private:
00736 // Helpers
00737 static void MakeInstance();
00738 static void LOKI_C_CALLING_CONVENTION_QUALIFIER
00738b DestroySingleton();
00739
00740 // Protection
00741 SingletonHolder();
00742
00743 // Data
00744 typedef typename
00744b ThreadingModel<T*,MutexPolicy>::VolatileType
00744c PtrInstanceType;
00745 static PtrInstanceType pInstance_;
00746 static bool destroyed_;
00747 };

[...]

00775 // SingletonHolder::Instance
00777
00778 template
00779 <
00780 class T,
00781 template <class> class CreationPolicy,
00782 template <class> class LifetimePolicy,
00783 template <class, class> class ThreadingModel,
00784 class MutexPolicy
00785 >
00786 inline T& SingletonHolder<T, CreationPolicy,
00787 LifetimePolicy, ThreadingModel, MutexPolicy>::Instance()
00788 {
00789 if (!pInstance_)
00790 {
00791 MakeInstance();
00792 }
00793 return *pInstance_;
00794 }



Here's Threads.h containing ThreadingModel.


00252 template < class Host, class MutexPolicy =
00252b LOKI_DEFAULT_MUTEX >
00253 class ObjectLevelLockable
00254 {
00255 mutable MutexPolicy mtx_;
00256
00257 public:
00258 ObjectLevelLockable() : mtx_() {}
00259
00260 ObjectLevelLockable(const ObjectLevelLockable&) :
00260b mtx_() {}
00261
00262 ~ObjectLevelLockable() {}
00263
00264 class Lock;
00265 friend class Lock;
00266
00269 class Lock
00270 {
00271 public:
00272
00274 explicit Lock(const ObjectLevelLockable& host) :
00274b host_(host)
00275 {
00276 host_.mtx_.Lock();
00277 }
00278
00280 explicit Lock(const ObjectLevelLockable* host) :
00280b host_(*host)
00281 {
00282 host_.mtx_.Lock();
00283 }
00284
00286 ~Lock()
00287 {
00288 host_.mtx_.Unlock();
00289 }
00290
00291 private:
00293 Lock();
00294 Lock(const Lock&);
00295 Lock& operator=(const Lock&);
00296 const ObjectLevelLockable& host_;
00297 };
00298
00299 typedef volatile Host VolatileType;
00300
00301 typedef LOKI_THREADS_LONG IntType;
00302
00303 LOKI_THREADS_ATOMIC_FUNCTIONS
00304
00305 };


If you look at row 744b you see that he passes T* to ThreadingModel. If
you then look at row 299 you see that his VolatileType becomes a
volatile T*. He and me then do the exact same thing on row 793,
initializing a T& with a volatile T.

I tried to implement my own singleton by means of Modern C++ Design by
Alexandrescu (an excellent book by the way), but I got stuck when my
compiler started to complain. Actually, in the book in Section 6.10.3
Assembling SingletonHolder, p.151 he writes "The
ThreadingModel<T>::VolatileType type definition expands either to T or
volatile T, depending on the actual threading model."

Could it be that the compilers at the time he wrote the SingletonHolder
let through that volatile conversion, but now they don't?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on
DeMarcus <use_my_alias_here(a)hotmail.com> writes:

<snip></snip>

> I do the same as him. This is what he does.

<snip>Following code, at breaks in line numbering</snip>

> Here's Singleton.h
>
> 00717 template
> 00718 <
> 00719 typename T,
> 00720 template <class> class CreationPolicy = CreateUsingNew,
> 00721 template <class> class LifetimePolicy = DefaultLifetime,
> 00722 template <class, class> class ThreadingModel =
> 00722b LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
> 00723 class MutexPolicy = LOKI_DEFAULT_MUTEX
> 00724 >
> 00725 class SingletonHolder
> 00726 {
> 00727 public:

> 00733 static T& Instance();

> 00744 typedef typename
> 00744b ThreadingModel<T*,MutexPolicy>::VolatileType
> 00744c PtrInstanceType;
> 00745 static PtrInstanceType pInstance_;

> 00747 };
>
> [...]
>
> 00775 // SingletonHolder::Instance
> 00777
> 00778 template
> 00779 <
> 00780 class T,
> 00781 template <class> class CreationPolicy,
> 00782 template <class> class LifetimePolicy,
> 00783 template <class, class> class ThreadingModel,
> 00784 class MutexPolicy
> 00785 >
> 00786 inline T& SingletonHolder<T, CreationPolicy,
> 00787 LifetimePolicy, ThreadingModel, MutexPolicy>::Instance()
> 00788 {
> 00789 if (!pInstance_)
> 00790 {
> 00791 MakeInstance();
> 00792 }
> 00793 return *pInstance_;
> 00794 }
>
>
>
> Here's Threads.h containing ThreadingModel.
>
>
> 00252 template < class Host, class MutexPolicy =
> 00252b LOKI_DEFAULT_MUTEX >
> 00253 class ObjectLevelLockable
> 00254 {

> 00299 typedef volatile Host VolatileType;

> 00305 };
>
>
> If you look at row 744b you see that he passes T* to ThreadingModel. If
> you then look at row 299 you see that his VolatileType becomes a
> volatile T*.

Where Host at line 299 is a T*, then VolatileType is not volatile T* but
rather T* volatile; that is, a volatile pointer to T.

> He and me then do the exact same thing on row 793,
> initializing a T& with a volatile T.

Rather, Alexandrescu is initializing a T& with an l-value of type T. It
is his T* that is volatile, not what it points to.

Regards

Paul Bibbings

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Joshua Maurice on
On Mar 16, 6:42 pm, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
> Joshua Maurice wrote:
> > On Mar 15, 9:28 pm, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
> >> Hi,
>
> >> I try to implement a simplified version of Alexandrescu's
> >> Loki::SingletonHolder. Seehttp://loki-lib.sourceforge.net/html/a00670.html
> >> row 717.
>
> >> My code looks like this.
>
> >> [...]
>
> >> What am I doing wrong?
>
> > Well, for starters, why are you using the volatile keyword? Do you
> > think it's a portable threading construct? It's not. volatile in C and
> > C++ has nothing to do with threading. The C and C++ standards do not
> > talk about threads, so anything they say about volatile is irrelevant.
> > By POSIX, volatile means nothing special for threading. (The Microsoft
> > compiler under certain versions does claim to make it like a mutex
> > acquire and release, but let's just ignore this bad form for now. Use
> > boost or ACE or some portable library if you need atomic functions, or
> > wait for the new C++ standard. At worst, wrap volatile yourself to not
> > litter your code with a not portable construct + usage.)
>
> This makes me very confused. I've always been taught to use the volatile
> keyword in front of variables that can be accessed from several threads.

I'm sorry that you were taught incorrectly. I suggest reading the
paper:
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
It's a much more thorough description of modern threading in C++, and
specifically the volatile keyword. Any programmer who uses threads
should read this paper and understand its implications.

This is a very common misconception. I would guess that it started
from poor teaching in schools and elsewhere. In the programming
courses I took in my college, I was taught a very simple and naive
threading model, just as most physicists are taught Newtonian
mechanics, except unlike the physicists and General Relativity and
quantum mechanics, I was never taught this naive threading model was
actually incorrect, that it's not how POSIX and WIN32 threads actually
work. I believe that most people who are taught threading are taught
this naive model first and never taught any better, and it's simply
perpetuated itself due to lack of understanding. This naive model is
part of the naive model of computers in general as executing source
code instructions faithfully, in order, without any changes. However,
in the real world, C++ (and other industry programming languages) have
the "as-if" rule which allows or is interpreted as allowing reordering
and changing of instructions of a single thread as long as the result
of that thread \in isolation\ is the same before and after the
modifications. This is the allowance for basically all optimizations.
To do otherwise in the presence of multiple threads would be \way\ too
great of a performance hit.

Specifically, if you do not understanding the following example, then
you do not understanding threading according to POSIX, WIN32, Java,
and I assume the new C++0x standard. (I assume that C++0x just copied
the essence of Java, POSIX, and WIN32 thread models. I haven't
actually read the new standard draft yet.)

// -- start pseudo code
#include "threading_library.hpp"
#include <iostream>
using namespace std;
int a = 0;
int b = 0;
void* foo(void* )
{ cout << a << " " << b << endl;
}
void* bar(void* )
{ a = 1;
b = 2;
}
int main()
{ start_thread(foo, 0);
start_thread(bar, 0);
}
// -- end code

Under POSIX and WIN32 guarantees (and Java guarantees if this was Java
code), this can print out any of the following:
0 0
0 2
1 0
1 2

Yes. The same compiled executable, when run multiple times, can print
any of the 4, perhaps changing at random between executions, for a
conforming compiler. Without a "happens-before" relationship (to
borrow the term from Java), the guarantees you have are really quite
small if any. If you want the proper "happens-before" relationship,
then use the proper synchronization. Simply put, there is no global
ordering on instructions when there are multiple threads. Different
threads might see different views of main memory. (Google cache
coherency.) This implies that you cannot correctly reason about
threading by simply examining the possible interleavings of
instructions as so commonly done because there is no guarantee of a
global ordering of instructions.

Coming full circle, volatile in C and C++ was not intended to
guarantee a global order across threads, no other standard such as
POSIX defines it as such (though visual studios compiler may), and
most compilers implement volatile as not guaranteeing a global order
across threads. Thus, volatile is not a portable threading construct
in C or C++.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Leigh Johnston on


"Joshua Maurice" <joshuamaurice(a)gmail.com> wrote in message
news:db73b48d-1504-473d-bb4f-9c6243c6372a(a)l12g2000prg.googlegroups.com...
<snip>
>> > Well, for starters, why are you using the volatile keyword? Do you
>> > think it's a portable threading construct? It's not. volatile in C and
>> > C++ has nothing to do with threading. The C and C++ standards do not
>> > talk about threads, so anything they say about volatile is irrelevant.
>> > By POSIX, volatile means nothing special for threading. (The Microsoft
>> > compiler under certain versions does claim to make it like a mutex
>> > acquire and release, but let's just ignore this bad form for now. Use
>> > boost or ACE or some portable library if you need atomic functions, or
>> > wait for the new C++ standard. At worst, wrap volatile yourself to not
>> > litter your code with a not portable construct + usage.)
>>
>> This makes me very confused. I've always been taught to use the volatile
>> keyword in front of variables that can be accessed from several threads.
>
> I'm sorry that you were taught incorrectly. I suggest reading the
> paper:
> http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
> It's a much more thorough description of modern threading in C++, and
> specifically the volatile keyword. Any programmer who uses threads
> should read this paper and understand its implications.
>
> This is a very common misconception. I would guess that it started
> from poor teaching in schools and elsewhere. In the programming
> courses I took in my college, I was taught a very simple and naive
> threading model, just as most physicists are taught Newtonian
> mechanics, except unlike the physicists and General Relativity and
> quantum mechanics, I was never taught this naive threading model was
> actually incorrect, that it's not how POSIX and WIN32 threads actually
> work. I believe that most people who are taught threading are taught
> this naive model first and never taught any better, and it's simply
> perpetuated itself due to lack of understanding. This naive model is
> part of the naive model of computers in general as executing source
> code instructions faithfully, in order, without any changes. However,
> in the real world, C++ (and other industry programming languages) have
> the "as-if" rule which allows or is interpreted as allowing reordering
> and changing of instructions of a single thread as long as the result
> of that thread \in isolation\ is the same before and after the
> modifications. This is the allowance for basically all optimizations.
> To do otherwise in the presence of multiple threads would be \way\ too
> great of a performance hit.
>
>
> Coming full circle, volatile in C and C++ was not intended to
> guarantee a global order across threads, no other standard such as
> POSIX defines it as such (though visual studios compiler may), and
> most compilers implement volatile as not guaranteeing a global order
> across threads. Thus, volatile is not a portable threading construct
> in C or C++.
>

You are incorrect to claim that volatile as defined by the current C++
standard has no use in multi-threaded programming. Whilst volatile does not
guarantee atomicity nor memory ordering across multiple threads the fact
that it prevents the compiler from caching vales in registers is useful and
perhaps essential. From Modern C++ Design:

"The volatile qualifier applied to a type tells the compiler that values of
that type might be changed by multiple threads. Knowing this, the compiler
avoids some optimizations (such as keeping values in internal registers)
that would make multithreaded code run erratically".

Just because there is no mention of threads in the current C++ standard does
not mean that the vast majority of C++ compilers don't implement volatile in
such a way that it is useful in multi-threaded designs.

Obviously the volatile keyword may not cause a memory barrier instruction to
be emitted but this is a side issue. The combination of a memory barrier
and volatile makes multi-threaded code work.

The goal when writing multi-threaded code though should be to minimize
shared state the result of which should mean very few volatile objects in
your code.

/Leigh



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]