2011-03-30 2 views
0

NSRecursiveLock을 사용하여 백그라운드 스레드에서 작업이 완료 될 때까지 의도적으로 대기 할 수 있습니까? 여기에 예제가 있습니다 :NSRecursive 잠금을 사용하여 작업이 완료 될 때까지 대기합니다.

나는 비동기 또는 동기가 될 수있는 loadParts 함수를 갖고 싶은 클래스가 있습니다. 비동기 함수는 일찍 호출되어 데이터가 실제로 필요하기 전에 부품을로드 할 수 있습니다. 동기식 데이터는 데이터가로드되었는지 또는 현재로드 중인지를 확인해야합니다. 로드 된 경우 데이터를 반환 할 수 있습니다. 현재로드 된 경우,로드 될 때까지 기다린 후 리턴해야합니다. 로드되고 있지 않은 경우에도 동 기적으로로드해야합니다. 이것은 사용하려고 시도하는 코드입니다.

// Private function to be run either on main thread or 
// background thread 
-(void)_loadParts 
{ 
    [_loadingPartsLock lock]; 
    _loadingParts = YES; 

    // Do long loading operation 

    _loadingParts = NO; 
    _partsLoaded = YES; 
    [_loadingPartsLock unlock]; 
} 

// Asynchronous loading of parts 
-(void)preloadParts 
{ 
    if(_loadingParts || _partsLoaded) 
     return; 

    [self performSelectorInBackground:@selector(_loadParts) withObject:nil]; 
} 

// Synchronous loading of parts 
-(void)loadParts 
{ 
    if(_loadingParts) 
    { 
     [_loadingPartsLock lock]; 
     [_loadingPartsLock unlock]; 
    } 

    if(!_partsLoaded) 
    { 
     [self _loadParts]; 
    } 
} 

이렇게하는 것이 안전하고 효율적인 방법입니까? 이미 몇 가지 문제가 있습니다. 잠금없이 BOOL의 값을 설정하고 테스트하는 것이 안전합니까? 또한 백그라운드 스레드가로드되는 동안 호출되는 경우 동기 함수에서 두 번 잠글 수 있습니다.

이 기능을 구현하는 더 일반적인 방법이 있습니까?

감사합니다.

+0

나는 우리가 NSCondition이 왜이 생각 여기에 내가 생각 해낸 코드입니다. –

답변

0

bbum의 답변에 영감을 얻은 결과, NSOperationQueue를 사용하는 솔루션을 발견했지만 그 방법에 대해서는 설명하지 않았습니다. 내 preloadParts 함수에서 백그라운드 스레드 함수를 실행하는 NSInvocationOperation의 인스턴스 인로드 연산을 만들고 저장합니다. 그런 다음 NSOperationQueue에 추가합니다.

언제든지 다른 클래스에서 데이터를 요청할 수 있습니다. 우선 데이터가로드되었는지 (변수가 설정되었는지) 확인합니다. 그렇지 않다면 작업이 대기열에 있는지 확인합니다. 그렇다면 [_loadOperation waitUntilFinished]를 호출합니다. 그렇지 않으면 waitUntilFinished 인수와 함께 작업 큐에 추가합니다.

-(void)preloadCategories 
{ 
    if([[_operationQueue operations] containsObject:_loadOperation]) 
     return; 

    [_operationQueue addOperation:_loadOperation]; 
} 

-(CCPart*)getCategoryForName:(NSString*)name 
{ 
    if(nil == _parts) 
    { 
     [self loadCategories]; 
    } 
    return [_parts objectForKey:name]; 
} 

-(void)loadCategories 
{ 
    if(nil != _parts) 
     return; 

    if([[_operationQueue operations] containsObject:_loadOperation]) 
    { 
     [_loadOperation waitUntilFinished]; 
    } 
    else 
    { 
     [_operationQueue addOperations:[NSArray arrayWithObject:_loadOperation] 
        waitUntilFinished:YES]; 
    } 
} 

-(void)_loadCategories 
{ 
    // Function that actually does the loading and sets _parts to be an array of the data 
    _parts = [NSArray array]; 
} 

초기화 함수에서 다음과 같이 나는 _operationQueue 및 _loadOperation을 설정 :

_operationQueue = [[NSOperationQueue alloc] init]; 
      _loadOperation = [[NSInvocationOperation alloc] initWithTarget:self 
                    selector:@selector(_loadCategories) 
                    object:nil]; 
3

더 먼 해결책은 dispatch_queue 또는 NSOperationQueue (직렬 작업으로 구성)을 사용하는 것입니다.

로딩 작업을 큐에 넣은 다음 완료되면 수행해야하는 작업을 모두 대기열에 추가합니다. "완료"작업이 "주 스레드에 업데이트하라"는 경우, 현재로드 된 데이터에 대한 응답으로 업데이트를 트리거하는 이벤트 인 주 스레드에서 메서드를 수행하십시오.

이렇게하면 잠겨있는 문제와 오버 헤드를 완전히 방지하면서 일종의 폴링 메커니즘을 요구하지 않고 "완료되었습니다"알림 문제를 해결할 수 있습니다.

+0

답해 주셔서 감사합니다. 데이터로드가 완료되면 필요한 조치를 취할 필요가 없습니다. 대부분이 작업은 사전에 잘 호출되며 문제가 발생하지 않습니다 (데이터로드에 충분한 시간이 있음). 데이터가 끝나지 않으면로드가 끝날 때까지 스레드를 차단하는 최악의 경우를 대비해야합니다. 이 클래스는 내가 만들고있는 프레임 워크에 대한 공용 클래스이므로 사용자가 콜백 또는 그와 비슷한 것을 등록하는 것에 대해 걱정할 필요가 없도록하고 싶습니다. – drewag

관련 문제