Program Club

Grand Central Dispatch에서 dispatch_sync 사용

proclub 2020. 10. 20. 18:47
반응형

Grand Central Dispatch에서 dispatch_sync 사용


누구든지 dispatch_syncin 의 목적이 무엇인지 정말 명확한 사용 사례로 설명 할 수 있습니까 GCD? 나는 이것을 왜 사용 해야하는지 이해할 수 없습니다.

감사!


블록을 실행하고 결과를 기다릴 때 사용합니다.

이에 대한 한 가지 예는 동기화를 위해 잠금 대신 디스패치 큐를 사용하는 패턴입니다. 예를 들어, a디스패치 큐에 의해 조정되는 액세스 가있는 공유 NSMutableArray가 있다고 가정합니다 q. 백그라운드 스레드가 배열에 추가 (비동기)하는 동안 포 그라운드 스레드가 첫 번째 항목을 (동 기적으로) 끌어낼 수 있습니다.

NSMutableArray *a = [[NSMutableArray alloc] init];
// All access to `a` is via this dispatch queue!
dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", NULL);

dispatch_async(q, ^{ [a addObject:something]; }); // append to array, non-blocking

__block Something *first = nil;            // "__block" to make results from block available
dispatch_sync(q, ^{                        // note that these 3 statements...
        if ([a count] > 0) {               // ...are all executed together...
             first = [a objectAtIndex:0];  // ...as part of a single block...
             [a removeObjectAtIndex:0];    // ...to ensure consistent results
        }
});

먼저 동생을 이해 dispatch_async

//Do something
dispatch_async(queue, ^{
    //Do something else
});
//Do More Stuff

dispatch_async새 스레드를 만드는 데 사용 합니다. 그렇게하면 현재 스레드가 중지되지 않습니다. 즉, 완료 //Do More Stuff되기 전에 실행될 수 있습니다.//Do something else

현재 스레드를 중지하려면 어떻게됩니까?

파견은 일절 사용하지 않습니다. 정상적으로 코드를 작성하십시오.

//Do something
//Do something else
//Do More Stuff

이제 다른 스레드 에서 무언가를하고 싶지만 마치 기다렸다가 작업이 연속적 으로 수행되는지 확인하십시오 .

이렇게하는 데는 여러 가지 이유가 있습니다. 예를 들어 UI 업데이트는 메인 스레드에서 수행됩니다.

그것이 당신이 사용하는 곳입니다 dispatch_sync

//Do something
dispatch_sync(queue, ^{
    //Do something else
});
//Do More Stuff

여기있어 //Do something //Do something else//Do More stuff하더라도 연속적으로 수행 //Do something else다른 스레드에서 수행된다.

일반적으로 사람들이 다른 스레드를 사용할 때 전체 목적은 무언가를 기다리지 않고 실행할 수 있도록하는 것입니다. 많은 양의 데이터를 다운로드하고 싶지만 UI를 원활하게 유지하고 싶다고 가정 해 보겠습니다.

따라서 dispatch_sync는 거의 사용되지 않습니다. 하지만 거기에 있습니다. 개인적으로 사용하지 않았습니다. dispatch_sync를 사용하는 샘플 코드 나 프로젝트를 요청하지 않는 이유는 무엇입니까?


dispatch_sync는 의미 상 기존 뮤텍스 잠금과 동일합니다.

dispatch_sync(queue, ^{
    //access shared resource
});

다음과 동일하게 작동합니다.

pthread_mutex_lock(&lock);
//access shared resource
pthread_mutex_unlock(&lock);

David Gelhar 는 자신의 예제가 조용히 직렬 대기열을 생성했기 때문에 작동한다고 말하지 않았습니다 (DISPATCH_QUEUE_SERIAL과 동일한 dispatch_queue_create에서 NULL을 전달 함).

동시 대기열을 생성하려는 경우 (모든 멀티 스레드 성능을 얻기 위해), 그의 코드는 변이 (removeObjectAtIndex :) 중 NSArray 변이 (addObject :) 또는 잘못된 액세스 (NSArray 범위 초과)로 인해 충돌이 발생할 수 있습니다. 이 경우 배리어를 사용하여 두 블록이 모두 실행되는 동안 NSArray에 대한 독점 액세스를 보장해야합니다. NSArray가 실행되는 동안 다른 모든 쓰기를 제외 할뿐만 아니라 다른 모든 읽기도 제외하여 수정을 안전하게 만듭니다.

동시 대기열의 예는 다음과 같습니다.

NSMutableArray *a = [[NSMutableArray alloc] init];
// All access to `a` is via this concurrent dispatch queue!
dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", DISPATCH_QUEUE_CONCURRENT);

// append to array concurrently but safely and don't wait for block completion
dispatch_barrier_async(q, ^{ [a addObject:something]; }); 

__block Something *first = nil;
// pop 'Something first' from array concurrently and safely but wait for block completion...
dispatch_barrier_sync(q, ^{                        
        if ([a count] > 0) {               
             first = [a objectAtIndex:0];  
             [a removeObjectAtIndex:0];    
        }
});
// ... then here you get your 'first = [a objectAtIndex:0];' due to synchronised dispatch.
// If you use async instead of sync here, then first will be nil.

실용적인 샘플을 원한다면이 질문을보십시오.

가끔 발생하는이 교착 상태를 어떻게 해결합니까?

내 주 managedObjectContext가 주 스레드에 생성되었는지 확인하여 문제를 해결합니다. 이 과정은 매우 빠르며 기다릴 필요가 없습니다. 기다리지 않는다는 것은 많은 동시성 문제를 처리해야한다는 것을 의미합니다.

코드가 실행되는 스레드와 다른 스레드 인 메인 스레드에서 일부 코드를 수행해야하므로 dispatch_sync가 필요합니다.

따라서 기본적으로 코드를 1로 설정하려면 평소처럼 진행하십시오. 경쟁 조건에 대해 걱정하고 싶지 않습니다. 계속 진행하기 전에 코드가 완성되었는지 확인하고 싶습니다. 2. 다른 스레드에서 수행

dispatch_sync를 사용하십시오.

1을 위반하면 dispatch_async를 사용합니다. 2를 위반하면 평소처럼 코드를 작성하십시오.

지금까지는 메인 스레드에서 무언가를해야 할 때이 작업을 한 번만 수행했습니다.

그래서 여기에 코드가 있습니다 :

+(NSManagedObjectContext *)managedObjectContext {


    NSThread *thread = [NSThread currentThread];
    //BadgerNewAppDelegate *delegate = [BNUtilitiesQuick appDelegate];
    //NSManagedObjectContext *moc = delegate.managedObjectContext;

    if ([thread isMainThread]) {
        //NSManagedObjectContext *moc = [self managedObjectContextMainThread];
        return [self managedObjectContextMainThread];
    }
    else{
        dispatch_sync(dispatch_get_main_queue(),^{
            [self managedObjectContextMainThread];//Access it once to make sure it's there
        });
    }

    // a key to cache the context for the given thread
    NSMutableDictionary *managedObjectContexts =[self thread].managedObjectContexts;

    @synchronized(self)
    {
        if ([managedObjectContexts objectForKey:[self threadKey]] == nil ) {
            NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
            threadContext.parentContext = [self managedObjectContextMainThread];
            //threadContext.persistentStoreCoordinator= [self persistentStoreCoordinator]; //moc.persistentStoreCoordinator;//  [moc persistentStoreCoordinator];
            threadContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
            [managedObjectContexts setObject:threadContext forKey:[self threadKey]];
        }
    }


    return [managedObjectContexts objectForKey:[self threadKey]];
}

dispatch_sync is mainly used inside dispatch_async block to perform some operations on main thread(like update ui).

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //Update UI in main thread
    dispatch_sync(dispatch_get_main_queue(), ^{
      self.view.backgroundColor = color;
    });
});

Here's a half-way realistic example. You have 2000 zip files that you want to analyze in parallel. But the zip library isn't thread-safe. Therefore, all work that touches the zip library goes into the unzipQueue queue. (The example is in Ruby, but all calls map directly to the C library. "apply", for example, maps to dispatch_apply(3))

#!/usr/bin/env macruby -w

require 'rubygems'
require 'zip/zipfilesystem'

@unzipQueue = Dispatch::Queue.new('ch.unibe.niko.unzipQueue')
def extractFile(n)
    @unzipQueue.sync do
        Zip::ZipFile.open("Quelltext.zip") {   |zipfile|
            sourceCode = zipfile.file.read("graph.php")
        }
    end
end

Dispatch::Queue.concurrent.apply(2000) do |i|
   puts i if i % 200 == 0
   extractFile(i)
end

I've used dispatch sync when inside an async dispatch to signal UI changes back to the main thread.

My async block holds back only a little and I know the main thread is aware of the UI changes and will action them. Generally used this in a processing block of code that takes some CPU time but I still want to action UI changes from within that block. Actioning the UI changes in the async block is useless as UI, I believe, runs on the main thread. Also actioning them as secondary async blocks, or a self delegate, results in the UI only seeing them a few seconds later and it looks tardy.

Example block:

dispatch_queue_t myQueue = dispatch_queue_create("my.dispatch.q", 0);
dispatch_async(myQueue,
^{

    //  Do some nasty CPU intensive processing, load file whatever

         if (somecondition in the nasty CPU processing stuff)
         {
             //  Do stuff
             dispatch_sync(dispatch_get_main_queue(),^{/* Do Stuff that affects UI Here */});
         }

 });

참고URL : https://stackoverflow.com/questions/4607125/using-dispatch-sync-in-grand-central-dispatch

반응형