2017-04-05 1 views
3

LLVM 컴파일러의 최적화 수준과 관련된 흥미로운 문제가 있습니다. 내가 사용하고 있습니다 :LLVM 컴파일러 - 최적화 버그입니까?

  • 엑스 코드 8.2.1
  • LLVM 8.0

예제 코드로 설명하는 것이 좋습니다. 저는 문제를 간단한 객관적인 수업으로 끓여 냈습니다. 먼저 아래의 코드를 참조하십시오 : 당신이 클래스 Foo를 인스턴스화하는 경우

@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 

load 메소드를 호출, 그것은로드 진행률을 시뮬레이션 비동기 로딩이 완료되었는지 확인하기 위해 is_loading 플래그를 준수합니다.

그리고 그 후

는 콘솔 출력은 다음과 같이 될 것입니다 :

started loading 
timer fired 
finished loading 

그러나 컴파일러 최적화를 켤 경우, 대신이 출력이 표시됩니다

started loading 
timer fired 

분명히 while 루프를 끝나지 않고 실행은 다음 printf() 메시지에 도달 할 수 없습니다.

명백한 이유가 없거나 최적화 프로그램 버그 일 수 있습니까?

답변

2

Apple이 synchronization page에 나와있는 것처럼 컴파일러는 코드가 최적화되었을 때 변수를 두 번 이상로드하지 않을 수도 있습니다. 다른 스레드에서 편집 할 수 있다는 것을 모릅니다.

변수를 volatile으로 표시하면 컴파일러가 필요할 때마다 값을로드해야하므로이 작업이 수행되지 않습니다.

+0

고마워, 그게 .. .. 'volatile'에 관한 나의 지식을 날인 할 때다. :) – scener

+1

간단히'volatile'을 추가하면 * 코드가 쓰레드를 안전하게 만들지 않는다. 그래서 계속 실패 할 것이다. –

+2

이 답변이 받아 들여지는 것은 불행합니다. 휘발성에 대한 바쁜 루핑은이 경우에는 작동하지만 CPU 사용량을 최대화하는 것과 같이 아주 나쁜 부작용이 있습니다. –

1

사미 (Sami)의 대답조차도 귀하의 질문에 대한 대답입니다. 오해의 소지가 있습니다.

volatile 이후 변수는 하지 스레드 안전, 전체 접근 방식은 블록을 형성 할 때 두 개의 서로 다른 스레드가 is_loading 액세스 실패 할 수 있습니다. volatile의 사용은 이 아니며 스레드 동기화를위한이 아닙니다.

대신 GCD 세마포어를 사용하십시오.