문제

나는 단지 GCD를 가지고 놀았고 장난감 코인 플립 퍼 앱을 썼습니다.

동전을 뒤집는 방법은 다음과 같습니다.

- (void)flipCoins:(NSUInteger)nFlips{

    // Create the queues for work
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);

    // Split the number of flips into whole chunks of kChunkSize and the remainder.
    NSUInteger numberOfWholeChunks = nFlips / kChunkSize;
    NSUInteger numberOfRemainingFlips = nFlips - numberOfWholeChunks * kChunkSize;

    if (numberOfWholeChunks > 0) {
        for (NSUInteger index = 0; index < numberOfWholeChunks; index++) {
            dispatch_async(queue, ^{
                NSUInteger h = 0;
                NSUInteger t = 0;
                flipTheCoins(kChunkSize, &h, &t);
                dispatch_async(mainQueue, ^{
                    self.nHeads += h;
                    self.nTails += t;
                });
            });
        }
    }
    if (numberOfRemainingFlips > 0) {
        dispatch_async(queue, ^{
            NSUInteger h = 0;
            NSUInteger t = 0;
            flipTheCoins(numberOfRemainingFlips, &h, &t);
            dispatch_async(mainQueue, ^{
                self.nHeads += h;
                self.nTails += t;
            });
        });

    }
}

보시다시피; 나는 백그라운드에서 그들을 뒤집고 메인 큐의 속성을 업데이트하는 큰 덩어리로 플립의 수를 깨고 있습니다. Window Controller에 의해 특성이 관찰되고 UI가 실행중인 결과로 업데이트됩니다.

동시성 프로그래밍 안내서와 GCD 문서를 살펴 보았습니다. 대기열을 중단하는 방법이 있지만 큐를 멈추고 객체를 실행하지 않고 모든 대기열을 제거 할 수있는 방법이 없습니다.

'정지'버튼을 연결하여 시작되면 뒤집기를 취소 할 수 있습니다. 와 함께 NSOperationQueue 나는 관찰 할 수있다 operationCount 그것이 실행 중인지 아는 재산 cancelAllOperations 대기열 블록을 제거합니다.

동시성 프로그래밍 안내서와 GCD 문서를 살펴 보았습니다. 대기열을 중단하는 방법이 있지만 큐를 멈추고 객체를 실행하지 않고 모든 대기열을 제거 할 수있는 방법이 없습니다.

그래서 :-

  1. 큐에 추가 된 블록이 여전히 기다리고 있는지 어떻게 알 수 있습니까?
  2. 아직 실행되지 않은 블록을 어떻게 취소합니까?
  3. 나는 GCD 재료를 처음 접 했으므로 제대로하고 있습니까?
도움이 되었습니까?

해결책

이것은 GCD로 프로그래밍 할 때 반 공동 질문입니다.

짧은 대답은 GCD에 큐에 대한 취소 API가 없다는 것입니다. 근거:

  1. 주어진 블록은 주어진 메모리 할당을 무료로 담당 할 수 있기 때문에 메모리 관리는 훨씬 더 복잡해집니다. 항상 블록을 실행함으로써 GCD는 메모리 관리가 쉽게 유지되도록합니다.
  2. 멈추는 것은 실제로 불가능합니다 달리기 부패 상태없이 차단.
  3. 취소 로직이 필요한 대부분의 코드는 이미 개인 데이터 구조에서 해당 상태를 추적하고 있습니다.

이러한 모든 경우가 주어지면 다음과 같은 코드를 작성하는 것이 훨씬 효율적이고 강력합니다.

dispatch_async(my_obj->queue, ^{
    bool done = false;
    // do_full_update() takes too long, therefore:
    while ( !my_obj->cancelled && !done ) {
        done = do_partial_update(my_obj);
    }
});

아, 그리고 대기열이 모든 큐인 블록 실행을 완료했는지 알기 위해 코드는 단순히 빈 블록을 동기 API :

dispatch_sync(my_obj->queue, ^{});

의견에서 언급했듯이 작업이 언제 이루어질 지 아는 더 나은 방법은 파견 그룹을 사용하는 것입니다. 모든 블록을 그룹으로 발송 한 다음 그룹에 완료 처리기를 추가 할 수 있습니다. 작업이 완료되면 완료 블록이 실행됩니다.

dispatch_group_t myGroup = dispatch_group_create();
dispatch_group_async(myGroup, my_obj->queue, ^{
    bool done = false;
    while ( !my_obj->cancelled && !done ) {
        done = do_partial_update(my_obj);
    }
});
dispatch_group_notify(myGroup, my_obj->queue, ^{
    NSLog(@"Work is done!");
    dispatch_release(myGroup);
});

모든 블록이 완료되면 그룹이 비어 있고 알림 블록을 트리거합니다. 거기에서 UI 등을 업데이트 할 수 있습니다.

행운을 빌고 재미있게 보내!

다른 팁

실행 중인지 말하는 방법

BOOL dispatch_queue_is_empty(dispatch_queue_t queue)
{
    dispatch_group_t group = dispatch_group_create();

    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        dispatch_group_leave(group);
    });

    int64_t maxWaitTime = 0.00000005 * NSEC_PER_SEC;
    BOOL isReady = dispatch_group_wait(group, maxWaitTime) == 0;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        dispatch_release(group);
    });

    return isReady;
}

앱에서 테스트합니다

dispatch_queue_t queue = dispatch_queue_create("test", 0);

NSLog(@"Is empty %@", dispatch_queue_is_empty(queue) ? @"YES" : @"NO");

dispatch_async(queue, ^{
    for(int i = 0; i < 100; i++)
    {
        NSLog(@"... %i", i);
    }
});

NSLog(@"Is empty %@", dispatch_queue_is_empty(queue) ? @"YES" : @"NO");

결과

Is empty YES
Is empty NO
... 0
... 1
... 2
... 3
... 4
... 5
... 6
... 7
... 8
... 9

변수의 기본값 maxWaitTime 원하는 결과로 조정할 수 있습니다.

일련의 디스패치 큐 또는 동시 발송 대기열이있는 경우, 동일한 작업을 수행 할 수있는 코드가 있습니다.

BOOL __block queueIsEmpty = false;
dispatch_barrier_async (_dispatchQueue, ^{
    queueIsEmpty = true;
});

while (!queueIsEmpty) {
    int i = 0;  // NOOP instruction
}

// At this point your queue should be empty.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top