2011-12-27 6 views
3

나는 세부 사항이 동시에 계산되고 업데이트되는 그림을 렌더링하고 회전하는 코드를 작성 중입니다. 단일 스레드 (디스플레이 링크 포함)에서 오류없이 작동하지만보기 흉한 것처럼 보입니다. 디스플레이 링크에 의해 계산이 시작되는 것을 원하지 않습니다. 그래서 메인 링크의 모든 OpenGL 관련 코드 (디스플레이 링크 포함)와 두 번째 스레드의 모든 계산 (while (YES) 루프 실행)을 실행하려고합니다.NSLock을 사용하지 않는 이유는 무엇입니까?

NSThread를 사용하여 구현했습니다. 그것은 아름답게 잠시 작동하고 glDrawArrays 중에 '스레드 1 : 프로그램 수신 신호 : EXC_BAD_ACCESS' '가 실패하고 때로는 이상한 그래픽이 깜박입니다. 이것은 주 스레드가 두 번째 스레드가 모델 레벨 데이터를 덮어 쓰는 동시에이 스레드를 읽으면 예상했던 것입니다.

그런 다음 모델 객체에 NSLock을 정의하고 내 모델 클래스의 모든 쓰기 및 내 뷰 클래스의 읽기를 위해 잠 갔지만 여전히 같은 오류가 발생할 수 있으며 그래픽은 여전히 때로는 이상한 플래시가 있습니다.

내가 여기 뭔가 잘못되었거나 다른 곳에서 문제가 있습니까?

둘째,이 경우 두 번째 스레드를 중지하는 올바른 방법은 무엇입니까? NSThread 클래스 참조는 취소, isCancelled 확인 및 종료를 제안하지만 exit 호출은 피해야합니다. 여기

코드에 대한 수정입니다 - 내 컨트롤러 클래스 (나는 ARC와 엑스 코드 4.2을 사용하고, 내 모든 인스턴스 변수 비 원자이다) :
@interface MyController : NSObject { 
    NSThread *calcThread; 
    ... 
} 
// (I do not give it an @property or @synthesize line) 

@implementation MyController 
- (void) awakeFromNib { 
    calcThread = [[NSThread alloc] initWithTarget:self 
      selector:@selector(calcLoop:) object:nil]; 
    [calcThread start]; 
    ... 
} 
- (void) calcLoop:(id)arg { 
    @autoreleasepool { 
     while (YES) 
      [myModel calculate]; 
    } 
} 
... 

내가 내 모델 클래스에 NSLock을 넣어 :

@interface MyModel : NSObject { 
    NSLock* oLock; 
    ... 
} 
@property (nonatomic, strong) NSLock* oLock; 

@implementation myModel 
-(id) init { 
    oLock = [[NSLock alloc] init]; 
    ... 
} 
-(void) changeModelAppearance { 
    [oLock lock]; 
    ... 
    [oLock unlock]; 
} 
... 

내보기 클래스의 :

@implementation MyView 
-(void) modelUpdated:(NSNotification *) notification { 
// modelUpdated is called via the NSNotificationCenter 
    MyModel* myModel = (MyModel*) [notification object]; 
    [myModel.oLock lock]; 
    ... // update OpenGL structures with data from myModel 
    [myModel.oLock unlock]; 
} 
... 

감사합니다!

+0

'glDrawArrays'를 (를) 호출하는 위치는 어디입니까? –

+0

'glDrawArrays'에 대한 호출은 다른 메소드 ('render')에서 뷰 클래스에 있습니다; 그것은 모델을 전혀 언급하지 않습니다. –

+0

NSNotificationCentre가 어떤 스레드에서든 호출 할 수 있기 때문에'modelUpdated' 메소드가'render' 메소드가 호출되는 동시에 OpenGL 구조체를 업데이트 할 수 있다는 것이 내 코드의 문제점 중 하나임을 깨달았습니다. 이제 modelUpdated에 두 번째 잠금을 삽입하고'glDrawArrays' 주위의 render 메소드에 넣습니다. 하지만 여전히 같은 오류가 발생합니다. –

답변

3

이 경우 그랜드 센트럴 디스패치를 ​​사용하면 훨씬 쉬울 것입니다.

@interface MyController : NSObject { // Not use why you're not inheriting from NSController here. 
    dispatch_queue_t calQueue; 
    ... 
} 

- (void) awakeFromNib { 
    calcQueue = dispatch_queue_create("com.yourApp.calc", DISPATCH_QUEUE_SERIAL); 
    dispatch_async(calcQueue, ^{ 
     while(YES) // This will peg the CPU at 100% 
      [myModel calculate]; 
    }); 
} 

모델 클래스

@interface MyModel : NSObject { 
    dispatch_queue_t modelQueue; 
    ... 
} 
@property dispatch_queue_t modelQueue; 

@implementation myModel 
-(id) init { 
    modelQueue = dispatch_queue_create("com.yourApp.model", DISPATCH_QUEUE_SERIAL); 
} 

-(void) dealloc { 
    dispatch_release(modelQueue); 
} 

-(void) changeModelAppearance { 
    dispatch_async(modelQueue, ^{ 
     ... 
    }); 
} 
... 

보기

@implementation MyView 
-(void) modelUpdated:(NSNotification *) notification { 
// modelUpdated is called via the NSNotificationCenter 
    MyModel* myModel = (MyModel*) [notification object]; 
    dispatch_async(model.modelQueue, ^{ 
     ... // update OpenGL structures with data from myModel 
    }); 
} 
... 

그냥 dispatch_suspend를 호출하고 타이머를 사용하는 경우 모든 큐의 사용을 dispatch_resume

를 다시 시작 대기열 중 하나를 일시 중지하려면 무한 루프 대신 CPU의 양을 줄일 수 있습니다. 노래.

calcTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); 
dispatch_source_set_timer(calcTimer, DISPATCH_TIME_NOW, DT, 1000); 
dispatch_source_set_event_handler(calcTimer, ^{ 
    ... 
}); 
dispatch_resume(calcTimer); 

이것은 훨씬 낮은 cpu 오버 헤드를 사용합니다.

+0

고마워요. 정말 고맙습니다. GCD가 도움이 될지 궁금합니다. 귀하의 첫 번째 거의 괄호 주석 "왜 NSController에서 상속하지 않는지"내가 코코아에 대해 얼마나 배워야하는지 깨달았습니다 ... 그리고 더 많이 읽은 후에 KVO를 사용하는 리팩토링과 특히 리셉셔니스트 패턴에 대해 생각하고 있습니다 이것은이 문제에 적합한 것으로 보인다. 저에게 빛을 보여 주셔서 고마워요! Cocoa Fundamentals Guide의 Receptionist 패턴에 대한 Apple의 설명에는 'NSOperationQueue'를 사용하여 여러 스레드에서 실행되는 코드가 포함되어 있습니다. –

관련 문제