Hi,
I am using g++ to compile my C++ code.
Here is the simplified code:
class A {
public:
void change();
void doSomething();
private:
volatile bool ready;
}
A::A() : ready(false) {}
A::change() {
printf("changed!\n");
ready=true;
}
A::doSomething() {
// the actual code is not an infinite loop but very close --
doSomething is being called at very high frequency without a while
loop.
while(true) {
if (ready) printf("it is ready\n");
else printf("it is not ready\n");
}
}
One of the threads will call A.change(), and another thread will call
A.doSomething().
Sometimes, I have the following output:
it is not ready
it is not ready
it is not ready
changed!
it is not ready
it is not ready
it is not ready
it is not ready
And I let the program continue for few minutes. It still prints "it
is not ready".
Any idea?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Hei
|
11/10/2009 2:28:56 AM |
|
On 10 Nov., 09:28, Hei <hchan1...@gmail.com> wrote:
> Hi,
>
> I am using g++ to compile my C++ code.
>
> Here is the simplified code:
>
> class A {
> public:
> void change();
> void doSomething();
> private:
> volatile bool ready;
>
> }
>
> A::A() : ready(false) {}
>
> A::change() {
> printf("changed!\n");
> ready=true;
>
> }
>
> A::doSomething() {
> // the actual code is not an infinite loop but very close --
> doSomething is being called at very high frequency without a while
> loop.
> while(true) {
> if (ready) printf("it is ready\n");
> else printf("it is not ready\n");
> }
>
> }
>
> One of the threads will call A.change(), and another thread will call
> A.doSomething().
> Sometimes, I have the following output:
> it is not ready
> it is not ready
> it is not ready
> changed!
> it is not ready
> it is not ready
> it is not ready
> it is not ready
>
> And I let the program continue for few minutes. It still prints "it
> is not ready".
>
> Any idea?
{ edits: quoted banner removed. please don't quote the banner. -mod }
Are you sure that you use the same instance of A when calling
doSomething?
Peer
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Peer
|
11/10/2009 7:02:37 AM
|
|
> And I let the program continue for few minutes. It still prints "it
> is not ready".
>
> Any idea?
Are you sure your threads are accessing the _same_ instance of class A you
are using and not that each thread is accessing it's own thread local copy?
You could test this easily by adding printfs to display "this" pointer & see
if they match!
void A::change() {
printf("change this=%p\n", this);
printf("changed!\n");
ready=true;
}
void A::doSomething() {
printf("doSomething this=%p\n", this);
while(true) {
if (ready) printf("it is ready\n");
else printf("it is not ready\n");
}
}
If they don't print equal then you are definately using different instances.
If they do print equal I'd need more code to see what the problem is.
Hope this helps.
Chris
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Chris
|
11/10/2009 7:03:06 AM
|
|
Hei wrote:
>
> And I let the program continue for few minutes. It still prints "it
> is not ready".
>
> Any idea?
>
Does the compiler's documentation tell you that this will work? The
language definition does not require volatile to impose synchronization
on a variable that's accessed from multiple threads. If one thread is
running on one CPU and the other thread on another CPU, writing from one
thread writes to that CPU's cache; the other CPU has its own cache, and
won't see that change until the write is flushed to main memory and the
previously read value is replaced from main memory. To make that happen,
you need synchronization; typically through a mutex or a condition variable.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Pete
|
11/10/2009 3:30:50 PM
|
|
On Nov 10, 9:28 am, Hei <hchan1...@gmail.com> wrote:
> Hi,
> volatile bool ready;
>
> A::A() : ready(false) {}
>
> A::change() {
> printf("changed!\n");
> ready=true;
>
> }
>
> A::doSomething() {
> // the actual code is not an infinite loop but very close --
> doSomething is being called at very high frequency without a while
> loop.
> while(true) {
> if (ready) printf("it is ready\n");
> else printf("it is not ready\n");
> }
>
> }
>
> One of the threads will call A.change(), and another thread will call
> A.doSomething().
The semantics of volatile are very specific, and they are intended to
read and write special memory locations (e.g. memory-mapped I/O
registers of periphery), not for thread communication. Volatile forces
the compiler to assume that the variable can change unexpectedly, that
simply writing or even reading it can have side effects, and thus to
never lift it to a register or reorder/omit accesses.
Volatile does not force the CPU(s) to do anything, though. You're
accessing a simple variable, an ordinary memory location. The CPU,
unlike the compiler, isn't fooled by you - it knows that no periphery
is going to change this location. Any core therefore can, depending on
the architecture's cache consistency model, hold the variable in its
private cache and keep reading the cached version, never noticing that
another core changed the memory location. What you need is atomic
access. Only then can you reliably and portably use a variable as a
ready flag.
Standard C++ doesn't yet have atomic variables. But various thread
libraries offer them.
All that said, if you're on an x86, all the above doesn't mean much,
because the architecture's cache consistency model should force the
change to be detected pretty soon.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
CornedBee
|
11/10/2009 3:32:15 PM
|
|
On Nov 10, 5:03 am, "Chris Morley" <chris.mor...@lineone.net> wrote:
> > And I let the program continue for few minutes. It still prints "it
> > is not ready".
>
> > Any idea?
>
> Are you sure your threads are accessing the _same_ instance of class A you
> are using and not that each thread is accessing it's own thread local copy?
>
> You could test this easily by adding printfs to display "this" pointer & see
> if they match!
>
> void A::change() {
> printf("change this=%p\n", this);
> printf("changed!\n");
> ready=true;
>
> }
>
> void A::doSomething() {
> printf("doSomething this=%p\n", this);
> while(true) {
> if (ready) printf("it is ready\n");
> else printf("it is not ready\n");
> }
>
> }
>
> If they don't print equal then you are definately using different instances.
> If they do print equal I'd need more code to see what the problem is.
>
> Hope this helps.
>
> Chris
I will give it a try later.
I believe that it is the same instance because if I restart the
program couple times, most the time, it works fine. Hence, I believe
that it is some racing condition...or I mis-interpret "volatile".
Thanks.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Hei
|
11/10/2009 3:40:40 PM
|
|
Hei schrieb:
> Hi,
>
> I am using g++ to compile my C++ code.
>
> Here is the simplified code:
>
> class A {
> public:
> void change();
> void doSomething();
> private:
> volatile bool ready;
> }
>
> A::A() : ready(false) {}
>
> A::change() {
> printf("changed!\n");
> ready=true;
> }
>
> A::doSomething() {
> // the actual code is not an infinite loop but very close --
> doSomething is being called at very high frequency without a while
> loop.
> while(true) {
> if (ready) printf("it is ready\n");
> else printf("it is not ready\n");
> }
> }
>
> One of the threads will call A.change(), and another thread will call
> A.doSomething().
> Sometimes, I have the following output:
> it is not ready
> it is not ready
> it is not ready
> changed!
> it is not ready
> it is not ready
> it is not ready
> it is not ready
>
> And I let the program continue for few minutes. It still prints "it
> is not ready".
>
> Any idea?
>
Volatile has nothing to do with threads (and ISO-C++ doesn't know
anything about threads until C++0x). You have to use a mutex to
synchronize the memory between your threads.
Lars
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Lars
|
11/10/2009 3:40:40 PM
|
|
On Nov 10, 8:28 am, Hei <hchan1...@gmail.com> wrote:
> volatile bool ready;
[...
> One of the threads will call A.change(), and another thread will call
> A.doSomething().
Judging from the subject of your article and the mention of threads
you seem to assume that volatile has anything to do with threading. In
C++ it has not. The volatile keyword merely indicates that the
*compiler* should not optimize accesses to the corresponding object in
any shape. That is, the compiler will diligently put in the
appropriate read and write instructions to access the data. However,
the CPU will see that there is no synchronization directive and decide
that it doesn't need to reread or flush the cache and hence never
notice the change. Well, maybe it will notice the change at some
point, maybe it will not.
The purpose of the volatile keyword is mainly to deal with changing
memory the CPU somehow knows is changing. For example, this may apply
to memory mapped I/O hardware: the CPU will be vary careful not to
cache this. Since the compiler was careful to do what the code says
rather than trying to be smart, this will just work nicely.
When you want to communicate data between multiple threads you always
need some form of synchronization. This can be as basic as
strategically positioned memory barriers but something is needed. I
understand that other languages use e.g. 'volatile int' for things the
upcoming C++ standard will call 'std::atomic<int>' but this has not
relevance whatsoever how things in C++ are done: neither the current C+
+ standard nor the upcoming C++ standard will make any guarantees with
respect to the use of 'volatile' and threading. You may have found
that in the past sprinkling 'volatile' keywords over the code somehow
helped but this was mostly [bad] luck.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
dietmar_kuehl
|
11/10/2009 11:13:55 PM
|
|
On 11月10日, 下午1時32分, CornedBee <wasti.r...@gmx.net> wrote:
> On Nov 10, 9:28 am, Hei <hchan1...@gmail.com> wrote:
>
>
>
> > Hi,
> > volatilebool ready;
>
> > A::A() : ready(false) {}
>
> > A::change() {
> > printf("changed!\n");
> > ready=true;
>
> > }
>
> > A::doSomething() {
> > // the actual code is not an infinite loop but very close --
> > doSomething is being called at very high frequency without a while
> > loop.
> > while(true) {
> > if (ready) printf("it is ready\n");
> > else printf("it is not ready\n");
> > }
>
> > }
>
> > One of the threads will call A.change(), and another thread will call
> > A.doSomething().
>
> The semantics ofvolatileare very specific, and they are intended to
> read and write special memory locations (e.g. memory-mapped I/O
> registers of periphery), not for thread communication.Volatileforces
> the compiler to assume that the variable can change unexpectedly, that
> simply writing or even reading it can have side effects, and thus to
> never lift it to a register or reorder/omit accesses.Volatiledoes not force the CPU(s) to do anything, though. You're
> accessing a simple variable, an ordinary memory location. The CPU,
> unlike the compiler, isn't fooled by you - it knows that no periphery
> is going to change this location. Any core therefore can, depending on
> the architecture's cache consistency model, hold the variable in its
> private cache and keep reading the cached version, never noticing that
> another core changed the memory location. What you need is atomic
> access. Only then can you reliably and portably use a variable as a
> ready flag.
> Standard C++ doesn't yet have atomic variables. But various thread
> libraries offer them.
>
> All that said, if you're on an x86, all the above doesn't mean much,
> because the architecture's cache consistency model should force the
> change to be detected pretty soon.
{ edits: quoted banner removed. please don't quote the banner. -mod }
I understand the part that "volatile" isn't a replacement for a
synchronization block. I don't know anything about the
"architecture's cache consistency model"...but I am running my program
on a x86_64 machine.
My original idea is to make the compiler not to optimize the code by
caching my variable in a register. I am okay that in runtime, the
core takes several sec to detect that the volatile variable has been
changed.
I was trying to avoid using mutex/lock to save some micro sec because
doSomething() is called very frequently.
So it sounds like my CPU isn't able to detect the change?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Hei
|
11/10/2009 11:18:59 PM
|
|
On 11月10日, 下午9時13分, "dietmar_ku...@yahoo.com"
<dietmar.ku...@gmail.com> wrote:
> On Nov 10, 8:28 am, Hei <hchan1...@gmail.com> wrote:
>
> > volatilebool ready;
> [...
> > One of the threads will call A.change(), and another thread will call
> > A.doSomething().
>
> Judging from the subject of your article and the mention of threads
> you seem to assume thatvolatilehas anything to do with threading. In
> C++ it has not. Thevolatilekeyword merely indicates that the
> *compiler* should not optimize accesses to the corresponding object in
> any shape. That is, the compiler will diligently put in the
> appropriate read and write instructions to access the data. However,
> the CPU will see that there is no synchronization directive and decide
> that it doesn't need to reread or flush the cache and hence never
> notice the change. Well, maybe it will notice the change at some
> point, maybe it will not.
>
> The purpose of thevolatilekeyword is mainly to deal with changing
> memory the CPU somehow knows is changing. For example, this may apply
> to memory mapped I/O hardware: the CPU will be vary careful not to
> cache this. Since the compiler was careful to do what the code says
> rather than trying to be smart, this will just work nicely.
>
> When you want to communicate data between multiple threads you always
> need some form of synchronization. This can be as basic as
> strategically positioned memory barriers but something is needed. I
> understand that other languages use e.g. 'volatileint' for things the
> upcoming C++ standard will call 'std::atomic<int>' but this has not
> relevance whatsoever how things in C++ are done: neither the current C+
> + standard nor the upcoming C++ standard will make any guarantees with
> respect to the use of 'volatile' and threading. You may have found
> that in the past sprinkling 'volatile' keywords over the code somehow
> helped but this was mostly [bad] luck.
>
My confusion came after I read this article: http://www.ddj.com/cpp/184403766
I thought volatile made the compiler not to cache the variable in a
register, and so each thread would get a most updated copy.
If I understand all the post correctly, even with volatile, a variable
can be cached in a CPU's cache, and CPU somehow can figure when to
flush if the variable is changed...such change has nothing to do with
threads at all?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Hei
|
11/11/2009 1:24:39 PM
|
|
Hi,
> I believe that it is the same instance because if I restart the
> program couple times, most the time, it works fine. Hence, I believe
> that it is some racing condition...or I mis-interpret "volatile".
There is new information here that it work most of the time! I assumed from
your original post that it was always broken. I'd also say then you have
some race condition.
Without more code it is difficult to suggest something concrete but I'd be
suspicious obviously of any code that writes to the bool. If that is only
change() & the constructor then are you sure the object is _always_
constructed before change() is called? Is it a static? Is it stack/heap
allocated and before _or_ after you fork the new threads... stick a printf
in the constructor. (i.e. is it possible you get the sequnce a.change();
a(); a.soSomethign()) Try wasting some time prior to the change() call so
burn so cycles in a loop or Sleep() (Windows or *nix equivalent) for 1s &
see what happens. I'm sure you have searched for accidental writes to ready.
Does it always work if you set the affinity to a single core? Try setting
ready to true in the constructor, does it print ready all the time as
expected or sometimes not ready?? Is ready only ever _written_ to in 1
thread or more?
Anyway, if you can force a change of behaviour (broken always or fixed
always) it should give you an idea where your problem actually lies.
If it is a synchronisation problem then either construct the A before going
into the threads or if that isn't possible you need to synchronise the
start - I'd suggest you use OS functions (e.g. WaitForSingleObject on
Windows) as they can freeze thread execution while they wait. Also OS is
easier than rolling your own sync.
Chris
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Chris
|
11/11/2009 1:29:01 PM
|
|
dietmar_kuehl@yahoo.com wrote:
> Judging from the subject of your article and the mention of threads
> you seem to assume that volatile has anything to do with threading.
> In C++ it has not.
Mark Rosewater, in his many columns about designing the trading
card game Magic The Gathering, often writes that one of the worst
things a game designer can do is to confound the expectations of
players as to how something works. Here's a sample column.
<http://www.wizards.com/magic/magazine/article.aspx?x=mtgcom/daily/mr333>
Given that so many people assume that volatile data and multiple
threads work together as a simple form of synchronization, perhaps
they should.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Hyman
|
11/11/2009 7:02:36 PM
|
|
On 10 Nov, 21:30, Pete Becker <p...@versatilecoding.com> wrote:
> Hei wrote:
>
> > And I let the program continue for few minutes. It still prints "it
> > is not ready".
>
> > Any idea?
>
> Does the compiler's documentation tell you that this will work? The
> language definition does not require volatile to impose synchronization
> on a variable that's accessed from multiple threads. If one thread is
> running on one CPU and the other thread on another CPU, writing from one
> thread writes to that CPU's cache; the other CPU has its own cache, and
> won't see that change until the write is flushed to main memory and the
> previously read value is replaced from main memory. To make that happen,
> you need synchronization; typically through a mutex or a condition variable.
This would be a good answer except for the ouput.
The two threads show interleaved writes to a stdout. This is either
unsupported and he just got lucky or the I/O susbsystem is protecting
itself with mutexes hence I am leaning towards the idea that the OP
hasn't actually done what he says that he has done.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Nick
|
11/11/2009 7:04:01 PM
|
|
Hyman Rosen wrote:
> dietmar_kuehl@yahoo.com wrote:
>> Judging from the subject of your article and the mention of threads
>> you seem to assume that volatile has anything to do with threading.
>> In C++ it has not.
>
> Mark Rosewater, in his many columns about designing the trading
> card game Magic The Gathering, often writes that one of the worst
> things a game designer can do is to confound the expectations of
> players as to how something works. Here's a sample column.
> <http://www.wizards.com/magic/magazine/article.aspx?x=mtgcom/daily/mr333>
>
> Given that so many people assume that volatile data and multiple
> threads work together as a simple form of synchronization, perhaps
> they should.
They do on some systems (as an extension).
It would be EXTREMELY expensive on other systems, where volatile is
actually used as originally intended - for accessing memory mapped
devices. Would you like a 128-way Itanium system do invalidate all
on-chip caches, just in case?
Bo Persson
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Bo
|
11/12/2009 8:19:28 PM
|
|
"Hei" <hchan1980@gmail.com>
> My confusion came after I read this article:
> http://www.ddj.com/cpp/184403766
Did you actually read it beyond the title?
It is about supplementing the code using sync with type system checks.
It neve claims volatile would be a replacement to using mutex and locking.
> I thought volatile made the compiler not to cache the variable in a
> register, and so each thread would get a most updated copy.
Then why class Counter in the article has that Mutex? And the other shown
classes?
> If I understand all the post correctly, even with volatile, a variable
> can be cached in a CPU's cache, and CPU somehow can figure when to
> flush if the variable is changed...such change has nothing to do with
> threads at all?
In short, volatile has little to o with threading itself.
http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/
AA just uses it as MAGIC to detect imprer access to a shared variable right
at compare time.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Balog
|
11/16/2009 3:05:03 PM
|
|
Balog Pal wrote:
> (...)
> In short, volatile has little to o with threading itself.
>
> http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/
>
I would like to highlight one point from the article:
[quote volatile-almost-useless-for-multi-threaded-programming]
Now consider issue (2). Sometimes programmers think of volatile as
turning off optimization of volatile accesses. That's largely true in
practice. But that's only the volatile accesses, not the non-volatile
ones. Consider this fragment:
volatile int Ready;
int Message[100];
void foo( int i ) {
Message[i/10] = 42;
Ready = 1;
}
It's trying to do something very reasonable in multi-threaded
programming: write a message and then send it to another thread. The
other thread will wait until Ready becomes non-zero and then read
Message. Try compiling this with "gcc -O2 -S" using gcc 4.0, or icc.
Both will do the store to Ready first, so it can be overlapped with the
computation of i/10. The reordering is not a compiler bug. It's an
aggressive optimizer doing its job.
[/quote]
I personally never thought of this problem -- guess I'll have to do
another grep on our codebase for volatile.
Just another point on the list to check before I can enable
optimizations in the release build. *Sigh* :)
br,
Martin
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Martin
|
11/17/2009 7:48:09 AM
|
|
On Nov 11, 11:24 am, Hei <hchan1...@gmail.com> wrote:
> My confusion came after I read this article:http://www.ddj.com/cpp/184403766
>
> I thought volatile made the compiler not to cache the variable in a
> register, and so each thread would get a most updated copy.
>
> If I understand all the post correctly, even with volatile, a variable
> can be cached in a CPU's cache, and CPU somehow can figure when to
> flush if the variable is changed...such change has nothing to do with
> threads at all?
Again, as others else-thread have mentioned, volatile was intended for
memory mapped IO, (and signal handlers, and communication between
setjump and longjump (sp)). The article http://www.ddj.com/cpp/184403766
is simply wrong. Very wrong. For a full description on why volatile is
useless in C++ as a portable threading construct, I point you to my
favorite (and correct) paper on the subject:
C++ and the Perils of Double-Checked Locking
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
The short version is that most compiler writers have decided that they
can break the "as if" rule between threads without correct
synchronization. The standard doesn't mention threads, so it's not
like it's breaking the standard. It's also the correct decision in
terms of the spirit and intent of the C++ standard (don't pay for what
you don't use, cost competitive with assembly, volatile is for memory
mapped IO).
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Joshua
|
11/17/2009 3:01:49 PM
|
|
On Nov 16, 1:05 pm, "Balog Pal" <p...@lib.hu> wrote:
> "Hei" <hchan1...@gmail.com>
> > My confusion came after I read this article:
> >http://www.ddj.com/cpp/184403766
>
> Did you actually read it beyond the title?
The better question is did \you\ actually read it beyond the title.
> It is about supplementing the code using sync with type system checks.
> It neve claims volatile would be a replacement to using mutex and locking.
Yes, it does.
Quoting ddj article
> Although both C and C++ Standards are conspicuously silent when it comes to threads, they do make a little concession to multithreading, in the form of the volatile keyword.
> Just like its better-known counterpart const, volatile is a type modifier. It's intended to be used in conjunction with variables that are accessed and modified in different threads. Basically, without volatile, either writing multithreaded programs becomes impossible, or the compiler wastes vast optimization opportunities. An explanation is in order.
The article goes on to suggest that the following is a
"correct" (albeit inefficient and slow), condition variable in multi-
threaded situations:
class Gadget
{
public:
void Wait()
{ while (!flag_)
Sleep(1000); // sleeps for 1000 milliseconds
}
void Wakeup() { flag_ = true; }
...
private:
volatile bool flag_;
};
Quote ddj article (in the context of flag_ not being volatile):
> Suppose the compiler figures out that Sleep(1000) is a call into an external library that cannot possibly modify the member variable flag_. Then the compiler concludes that it can cache flag_ in a register and use that register instead of accessing the slower on-board memory. This is an excellent optimization for single-threaded code, but in this case, it harms correctness: after you call Wait for some Gadget object, although another thread calls Wakeup, Wait will loop forever. This is because the change of flag_ will not be reflected in the register that caches flag_. The optimization is too ... optimistic. Caching variables in registers is a very valuable optimization that applies most of the time, so it would be a pity to waste it. C and C++ give you the chance to explicitly disable such caching. If you use the volatile modifier on a variable, the compiler won't cache that variable in registers � each access will hit the actual memory location of that variable. So all y
!
ou have to do to make Gadget's Wait/Wakeup combo work is to qualify flag_ appropriately:
[Insert code fragment with volatile flag_]
That piece of code when Wait and Wakeup are called from different
threads, despite whatever volatile qualification, is not correct
according to the C++ standard (as it doesn't mention threads). If it
was correct, that would be against the spirit of the C and C++
standard: (1- Volatile is for memory mapped IO, signal handlers, and
setjump longjump (sp). 2- Cost competitive with assembly. 3- Don't pay
for what you don't use.). It will not be correct in C++0x, which
includes descriptions of threading. Finally, according to the standard
threading library POSIX, it's actually wrong. (However, using the
other standard threading library, win32, the code fragment may be
correct with volatile. Go find a microsoft newsgroup or use the msdn
webpages for further details.)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Joshua
|
11/17/2009 8:13:37 PM
|
|
|
17 Replies
89 Views
(page loaded in 0.192 seconds)
|