【问题标题】:LLVM compiler - Is this an optimization bug?LLVM 编译器 - 这是一个优化错误吗?
【发布时间】:2017-08-31 07:14:02
【问题描述】:

我有一个与 LLVM 编译器的优化级别有关的有趣问题。我正在使用:

  • Xcode 8.2.1
  • LLVM 8.0

最好用示例代码来解释。我将问题归结为一个简单的objective-c 类。请先看下面的代码:

@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

如果你实例化类Foo并调用load方法,它将模拟一个加载进度并异步观察is_loading标志以确定加载是否完成。

之后,控制台输出会是这样的:

started loading
timer fired
finished loading  

但是如果你打开编译器优化,你会看到这样的输出:

started loading
timer fired

显然,while 循环永远不会结束,执行无法到达下一个 printf() 消息。

我是否遗漏了导致这种情况发生的明显原因,还是可能是优化器错误?

【问题讨论】:

    标签: ios objective-c xcode llvm compiler-optimization


    【解决方案1】:

    即使 Sami 的回答是对您 Q 的回答,也可能具有误导性。

    由于volatile 变量不是线程安全的,当块形成两个不同的线程访问is_loading 时,您的整个方法可能会失败。 volatile 的用法用于线程同步。

    改用 GCD 信号量。

    【讨论】:

      【解决方案2】:

      正如 Apple 在其 synchronization page 中所述,当优化代码时,编译器可能不会多次加载该变量。它不知道它可能是从另一个线程编辑的,所以会发生这种情况。

      将变量标记为volatile 将强制编译器在每次需要时加载该值,而这不会发生。

      【讨论】:

      • 谢谢你,这很有效.. 是时候把我对volatile 的知识抛之脑后了 :)
      • 我想补充一点,简单地添加volatile 确实不会使代码线程安全,所以它仍然会失败。
      • 不幸的是,这个答案被接受了。在这种情况下,对 volatile 进行忙循环可能会起作用,但它会产生一些非常讨厌的副作用,例如最大化 CPU 利用率。
      • @DietrichEpp 是的,应该说这不是正确的做事方式,但问题是为什么以这种方式优化代码。可以添加,但该信息已经有另一个答案。
      猜你喜欢
      • 2013-07-05
      • 2014-06-07
      • 1970-01-01
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      • 2021-04-24
      • 1970-01-01
      相关资源
      最近更新 更多