Reputation: 45
I have an interesting problem related to the optimization level of LLVM compiler. I'm using:
It is better to explain it with an example code. I boiled down the problem into a simple objective-c class. Please see the code below first:
@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 class Foo
and call load
method, it will simulate a loading progress and asynchronously observe is_loading
flag to determine if the loading is finished.
And after that, the console output will be like this:
started loading
timer fired
finished loading
But if you turn on the compiler optimization, you will see this output instead:
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 to happen, or can it be an optimizer bug?
Upvotes: 3
Views: 207
Reputation: 16650
Even Sami's answer is an answer to your Q, it maybe is misleading.
Since volatile
variables are not thread safe, your whole approach can fail, when blocks form two different threads access is_loading
. The usage of volatile
is not intended for thread synchronization.
Use GCD semaphores instead.
Upvotes: 1
Reputation: 31143
As Apple states on their synchronization page the compiler may well not load the variable more than once when the code is optimized. It doesn't know that it may be edited from another thread so this happens.
Marking the variable as volatile
will force the compiler to load the value each time it's needed and this won't happen.
Upvotes: 2