0

由于某种原因,在发布版本中有一个空的while循环会挂起,而在调试版本中它可以正常工作。此示例在调试中有效,但在发布中挂起:

//Wait for stream to open
while (!_isReadyForData);  

这是我想出的解决方案,以便让它在发布中工作:

//Wait for stream to open
while (!_isReadyForData)
{
   //For some reason in release mode, this is needed
   sleep(.5);
}

我只是好奇为什么我需要在代码循环块中添加一些东西。

4

1 回答 1

3

原因当然是由于编译器优化,正如评论中已经指出的那样。

记住 Objective-C 是建立在 C 之上的,我整理了一个具有不同优化级别的简单 C 示例,这就是结果。

原始代码

int main(int argc, char const *argv[])  {
    char _isReadyForData = 0;
    while (!_isReadyForData);
    return 0;
}

没有优化的 LLVM IR (-O0)

define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %_isReadyForData = alloca i8, align 1
  store i32 0, i32* %retval
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  store i8 0, i8* %_isReadyForData, align 1
  br label %while.cond

while.cond:                                       ; preds = %while.body, %entry
  %0 = load i8* %_isReadyForData, align 1
  %tobool = icmp ne i8 %0, 0
  %lnot = xor i1 %tobool, true
  br i1 %lnot, label %while.body, label %while.end

while.body:                                       ; preds = %while.cond
  br label %while.cond

while.end:                                        ; preds = %while.cond
  ret i32 0
}

具有 1 级优化的 LLVM IR (-O1)

define i32 @main(i32 %argc, i8** nocapture %argv) #0 {
entry:
  br label %while.cond

while.cond:                                       ; preds = %while.cond, %entry
  br label %while.cond
}

如您所见,编译器在优化时会产生一个无限循环,因为局部变量_isReadyForData在该上下文中是无用的,因此被删除。

正如@faffaffaff 所建议的,使用volatile关键字 on_isReadyForData可以解决问题。

具有 1 级优化 (-O1) 和 volatile 关键字的 LLVM IR

define i32 @main(i32 %argc, i8** nocapture %argv) #0 {
entry:
  %_isReadyForData = alloca i8, align 1
  store volatile i8 0, i8* %_isReadyForData, align 1
  br label %while.cond

while.cond:                                       ; preds = %while.cond, %entry
  %_isReadyForData.0.load1 = load volatile i8* %_isReadyForData, align 1
  %lnot = icmp eq i8 %_isReadyForData.0.load1, 0
  br i1 %lnot, label %while.cond, label %while.end

while.end:                                        ; preds = %while.cond
  ret i32 0
}

但我绝对同意@rmaddy 的说法,即您最好更改程序流程并使用驱动逻辑,而不是修补已有的内容。

于 2013-06-25T19:29:58.470 回答