|
From: K�r�at on 18 Jun 2008 10:37 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 18 Jun 2008 11:25 "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 18 Jun 2008 11:49 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 18 Jun 2008 12:16 "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 18 Jun 2008 12:36
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 > |