Is LLVM compiler an optimization bug?
I have an interesting issue related to the optimization level of the LLVM compiler. I use:
- Xcode 8.2.1
- LLVM 8.0
It is better to explain this with example code. I turned the problem into a simple objective-c class. First see the code below:
@interface Foo() {
BOOL is_loading;
}
@end
@implementation Foo
- (void)test {
printf("started loading \n");
// set loading flag to YES
is_loading = YES;
// schedule a timer to fire in 2 seconds, to simulate the end of loading
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(timerFired)
userInfo:nil
repeats:NO];
// wait asynchronously until loading flag is set to NO
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (is_loading) {
// loop until timer event modifies is_loading flag
}
printf("finished loading \n");
});
}
- (void)timerFired {
printf("timer fired \n");
// set loading flag to NO
is_loading = NO;
}
@end
If you instantiate the class Foo
and call the method load
, it will simulate the loading progress and asynchronously observe the flag is_loading
to determine if the loading has finished.
And after that, the console output will look like this:
started loading
timer fired
finished loading
But if you enable compiler optimizations, you will see this output:
started loading
timer fired
Apparently the while loop never ends, and execution cannot reach the next printf () message.
Am I missing an obvious reason for this, or could it be an optimizer bug?
source to share
As Apple states on the page, the compiler may not load the variable more than once when the code is optimized. He doesn't know that he might be edited from another thread, so this happens.
Marking the variable as volatile
will force the compiler to load the value every time it needs to, and it won't.
source to share
Even Sami's answer is the answer to your Q question, perhaps misleading.
Since variables volatile
are not thread safe, your whole approach can fail when blocks form two different access streams is_loading
. The use is volatile
not intended for thread synchronization.
Use GCD semaphores instead.
source to share