Re: Am I or Alexandrescu wrong about singletons?
On Mar 16, 6:42 pm, DeMarcus <use_my_alias_h...@hotmail.com> wrote:
Joshua Maurice wrote:
On Mar 15, 9:28 pm, DeMarcus <use_my_alias_h...@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! ]