Click to See Complete Forum and Search --> : Bug with Optimization Flags in .NET2003?


diehardii
October 7th, 2004, 08:22 AM
Hi everyone, I can't find a good reason for this and I was hoping someone here could enlighten me.
I have a (threaded) loop in my program. It pretty much just monitors a running process and if that process ends resets it. Under debug this runs just fine. When I go to release it hangs on the reset. Further testing showed that it isn't even getting to the reset instruction. So here's the weird part. If I add a Sleep(10) to the loop it works, or if I add another if..then statement it also works, however just the single if..then never gets called with the full optimization flag. I am genuinely very curious about this, considering I banged my head against the wall for awhile. What the heck???

~Steve

//Works
DWORD WINAPI Monitor(void* arguments)
{

while(g_monitorkill == false)
{
if(g_reset == true)
{
printf("What the heck\n");
}

if(g_reset == true)
{
printf("resetting\n");
Reset(Connection.IPaddress.c_str(),Connection.Port);
g_reset = false;
}
//Sleep(10);


}
return 0;
}

//Works

DWORD WINAPI Monitor(void* arguments)
{

while(g_monitorkill == false)
{
if(g_reset == true)
{
printf("resetting\n");
Reset(Connection.IPaddress.c_str(),Connection.Port);
g_reset = false;
}
Sleep(10);


}
return 0;
}

//Doesn't work????
DWORD WINAPI Monitor(void* arguments)
{

while(g_monitorkill == false)
{
if(g_reset == true)
{
printf("resetting\n");
Reset(Connection.IPaddress.c_str(),Connection.Port);
g_reset = false;
}

}
return 0;
}

jwbarton
October 7th, 2004, 08:39 AM
I assume that the various "g_*" variables are global variables.

The compiler normally will optimize assuming a single threaded program. The Monitor routine is only reading the variables while waiting for a g_reset. Since nothing in the loop is changing the variable, the optimizer assumes that it can't be changed, so optimizes it out of the loop. When you make a call to an external routine (like Sleep), the compiler doesn't know it the external routine might change the global variable, so it leaves the checks in the loop.

If you declare the variable as volatile, the compiler will assume that it can be changed external to the routine and won't optimize it away.

Another choice would be to use an event (look at the Win32 routine CreateEvent), which you can sleep on and won't take any additional processor time while the event isn't signalled.

Best regards,
John

diehardii
October 7th, 2004, 09:03 AM
I have the multithreaded dll option checked in the options. Does this not make a difference?

~Steve

jwbarton
October 7th, 2004, 09:33 AM
No, this option changes which libraries are used, but not what code is generated. It is still up to the programmer to handle issues of communication and synchronization between threads. The C++ language doesn't officially have any support for multi-threaded programming. The VC compiler normally just generates code assuming that it is a simple single-threaded environment. By using various objects that provided by Win32 (events, semaphores, critical sections, etc.) along with Win32 routines such as WaitForSingleObject/WaitForMultipleObjects, you can implement multi-threaded programs that work reasonably well.

harizak
October 7th, 2004, 09:55 AM
Since your problem seems to be resolved by inserting an additional command (actually execution delay) between the set and test operations on the g_reset variable, I can -almost safely- assume that there is a race condition and not an optimization problem with your code. Note that debug builds usually inject unnessecary code in the executable, which is required for debugging, and -in your case- also introduce a small execution delay.

Could you please post the code of the other thread, the one that by altering the value of the g_reset, forces the presented one to call the Reset function?

Regards,

--harizak

diehardii
October 8th, 2004, 05:16 PM
Hi harizak, it doesn't appear to be a race condition, as the only time g_reset is changed (besides the above function) is when the pertinent thread has died to reset everything. I am positive that thread is dead and the g_reset value changed upon thread completion. However, unless I put in something else in that function, it won't ever reset. Thanks for the help.

~Steve

Andreas Masur
October 8th, 2004, 05:22 PM
[ Moved thread ]

wien
October 8th, 2004, 07:12 PM
Most likely the compiler is optimizing the globals to reside inside a register during execution of the thread, and therefore the changes made by any other thread won't be reflected in the register-stored variable the thread is using.

To circumvent this situation you can declare the globals as volatile. That will inform the compiler that the variable in question can be changed at any time, even if the current thread didn't do it, and thus it can generate code to load the variable from memory instead of a register every time it is needed.

Also check out this (http://www.cuj.com/documents/s=7998/cujcexp1902alexandr/) interesting article on the usage of volatile.