From: K�r�at on
Hi all,

In an article about volatile qualifier there is a small code by which the
author explains a hidden bug which occurs if we neglect using volatile
qualifier. The code is simple :

class Gadget
{
public:
void Wait() { while (!flag) Sleep(1000); }
void Wakeup() { flag = true;}
private:
bool flag;
};

The author says :

"If we neglect to qualify the variable "flag" as "volatile" then the
compiler optimizes access to that variable by caching it in a register. This
is a good optimization in single threaded environments. No need to read
value of the flag every time. But in multithreaded environmens there is a
surprise. If you call Wait from Thread-1 and Wakeup from Thread-2 then the
Thread-1 will never get the actual value of the flag and loop forever."

As far as know, for this happen this two threads should run on different
processors or cores because of cache issues. Does this happen on a single
core? If yes what is the reason?

Thanks in advance.


From: Alex Blekhman on
"Krat" wrote:
> "If we neglect to qualify the variable "flag" as "volatile" then
> the compiler optimizes access to that variable by caching it in
> a register. [...]"
>
> As far as know, for this happen this two threads should run on
> different processors or cores because of cache issues. Does this
> happen on a single core? If yes what is the reason?

It happens all the same on a single core system. The author does
not speak about CPU cache here, but about abstract "caching"
optimization that compiler performs. Instead of reading the
variable from a memory on each access compiler reads it only once
and then stores the value in a register. It can be represented
with the following pseudocode:

; while statement
....
0001 mov ecx,byte ptr [flag]
flag_check:
0002 test ecx,ecx
0003 jne end_of_while
0004 ...
0005 jmp flag_check
end_of_while:
0006 ...

As you can see, after an execution of while's body the flow jumps
back to test the flag value without reading it from the memory. It
will behave exactly the same both on single and multi CPU system.

HTH
Alex


From: K�r�at on
Well, but what happens if the same thread calls the Wakeup () function
inside the while body? According to the author it works as expected in this
case. Ok, this is surely true but how the compiler decide which thread
modifying the variable?

"Alex Blekhman" <tkfx.REMOVE(a)yahoo.com> wrote in message
news:estEWeV0IHA.2384(a)TK2MSFTNGP02.phx.gbl...
> "Krat" wrote:
>> "If we neglect to qualify the variable "flag" as "volatile" then the
>> compiler optimizes access to that variable by caching it in a register.
>> [...]"
>>
>> As far as know, for this happen this two threads should run on different
>> processors or cores because of cache issues. Does this happen on a single
>> core? If yes what is the reason?
>
> It happens all the same on a single core system. The author does not speak
> about CPU cache here, but about abstract "caching" optimization that
> compiler performs. Instead of reading the variable from a memory on each
> access compiler reads it only once and then stores the value in a
> register. It can be represented with the following pseudocode:
>
> ; while statement
> ...
> 0001 mov ecx,byte ptr [flag]
> flag_check:
> 0002 test ecx,ecx
> 0003 jne end_of_while
> 0004 ...
> 0005 jmp flag_check
> end_of_while:
> 0006 ...
>
> As you can see, after an execution of while's body the flow jumps back to
> test the flag value without reading it from the memory. It will behave
> exactly the same both on single and multi CPU system.
>
> HTH
> Alex
>


From: Alex Blekhman on
"Krat" wrote:
> Well, but what happens if the same thread calls the Wakeup ()
> function inside the while body? According to the author it works
> as expected in this case.

If there is something inside the while body that is obscure for
the compiler, then "caching" optimization is not enabled. It
happens because the compiler cannot safely assume that the flag is
not accessed within the function. I suspect that the presence of
`Sleep' function will disable this optimization, as well.

> Ok, this is surely true but how the compiler decide which thread
> modifying the variable?

I am afraid that I am not following you. The compiler cannot
decide which thread modifying the variable. C++ compilers do not
understand threads, that's why the whole problem with "caching"
exists. You, as a developer, must ensure that the code behaves
correctly in the multithreaded environment. In this specific case
one should use `volatile' qualifier to disable possible
optimizations of `flag' variable.

Alex


From: K�r�at on
Well, I know the compiler do not care about thread scheduling :) I just want
to emphasize my incomprehension about author's idea.

Thank you.


"Alex Blekhman" <tkfx.REMOVE(a)yahoo.com> wrote in message
news:OhBFe6V0IHA.4964(a)TK2MSFTNGP02.phx.gbl...
> "Krat" wrote:
>> Well, but what happens if the same thread calls the Wakeup () function
>> inside the while body? According to the author it works as expected in
>> this case.
>
> If there is something inside the while body that is obscure for the
> compiler, then "caching" optimization is not enabled. It happens because
> the compiler cannot safely assume that the flag is not accessed within the
> function. I suspect that the presence of `Sleep' function will disable
> this optimization, as well.
>
>> Ok, this is surely true but how the compiler decide which thread
>> modifying the variable?
>
> I am afraid that I am not following you. The compiler cannot decide which
> thread modifying the variable. C++ compilers do not understand threads,
> that's why the whole problem with "caching" exists. You, as a developer,
> must ensure that the code behaves correctly in the multithreaded
> environment. In this specific case one should use `volatile' qualifier to
> disable possible optimizations of `flag' variable.
>
> Alex
>