Programing

교착 상태없이 동기식으로 메인 큐를 디스패치하는 방법은 무엇입니까?

lottogame 2020. 12. 2. 07:45
반응형

교착 상태없이 동기식으로 메인 큐를 디스패치하는 방법은 무엇입니까?


메인 큐의 블록을 동 기적으로 디스패치해야합니다. 현재 메인 스레드에서 실행 중인지 여부를 모르겠습니다. 순진한 솔루션은 다음과 같습니다.

dispatch_sync(dispatch_get_main_queue(), block);

그러나 현재 메인 큐에서 실행중인 블록 내부에있는 경우이 호출은 교착 상태를 만듭니다. (동기식 디스패치는 블록이 완료 될 때까지 기다리지 만 현재 블록이 완료되기를 기다리고 있기 때문에 블록은 실행을 시작하지도 않습니다.)

분명한 다음 단계는 현재 대기열을 확인하는 것입니다.

if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
    block();
} else {
    dispatch_sync(dispatch_get_main_queue(), block);
}

이것은 작동하지만 추악합니다. 적어도 일부 사용자 지정 함수 뒤에 숨기기 전에이 문제에 대한 더 나은 해결책이 있습니까? 저는 비동기 적으로 블록을 디스패치 할 여유가 없다는 점을 강조합니다. 앱은 비동기 적으로 디스패치 된 블록이 "너무 늦게"실행되는 상황에 있습니다.


Mac 및 iOS 응용 프로그램 내에서 이와 같은 것을 상당히 정기적으로 사용해야하므로 다음 도우미 기능을 사용합니다 (원래이 답변에 설명되어 있음 ).

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

당신이 통해 전화

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

이것은 위에서 설명한 프로세스와 거의 비슷하며, 이와 같은 것을 독자적으로 제작 한 여러 다른 개발자와 이야기했습니다.

그 기능에 대한 경고 섹션 이 ID 테스트를 위해 이것을 사용하는 것에 대해 경고 한 적이 있고 iOS 6에서 호출이 더 이상 사용되지 않기 때문에 [NSThread isMainThread]확인 하는 대신 사용했습니다 .dispatch_get_current_queue()


기본 대기열 또는 기본 스레드에서 동기화하기 위해 (동일하지 않음) 다음을 사용합니다.

import Foundation

private let mainQueueKey    = UnsafeMutablePointer<Void>.alloc(1)
private let mainQueueValue  = UnsafeMutablePointer<Void>.alloc(1)


public func dispatch_sync_on_main_queue(block: () -> Void)
{
    struct dispatchonce  { static var token : dispatch_once_t = 0  }
    dispatch_once(&dispatchonce.token,
    {
        dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey, mainQueueValue, nil)
    })

    if dispatch_get_specific(mainQueueKey) == mainQueueValue
    {
        block()
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(),block)
    }
}

extension NSThread
{
    public class func runBlockOnMainThread(block: () -> Void )
    {
        if NSThread.isMainThread()
        {
            block()
        }
        else
        {
            dispatch_sync(dispatch_get_main_queue(),block)
        }
    }

    public class func runBlockOnMainQueue(block: () -> Void)
    {
        dispatch_sync_on_main_queue(block)
    }
}

I recently began experiencing a deadlock during UI updates. That lead me this Stack Overflow question, which lead to me implementing a runOnMainQueueWithoutDeadlocking-type helper function based on the accepted answer.

The real issue, though, is that when updating the UI from a block I had mistakenly used dispatch_sync rather than dispatch_async to get the Main queue for UI updates. Easy to do with code completion, and perhaps hard to notice after the fact.

So, for others reading this question: if synchronous execution is not required, simply using dispatch_**a**sync will avoid the deadlock you may be intermittently hitting.

참고URL : https://stackoverflow.com/questions/10330679/how-to-dispatch-on-main-queue-synchronously-without-a-deadlock

반응형