在Grand Central Dispatch中使用dispatch_sync

时间:2011-01-05 17:26:03

标签: cocoa ios ios4 grand-central-dispatch

任何人都可以用非常明确的用例来解释dispatch_syncGCD的目的是什么?我无法理解我必须使用它的地点和原因。

谢谢!

8 个答案:

答案 0 :(得分:77)

首先了解其兄弟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的示例代码或项目。

答案 1 :(得分:76)

当您想要执行一个块并等待结果时,可以使用它。

这方面的一个示例是您使用调度队列而不是锁来进行同步的模式。例如,假设您有一个共享的NSMutableArray a,其访问权限由调度队列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
        }
});

答案 2 :(得分:25)

答案 3 :(得分:4)

David Gelhar没有说明他的示例只会因为他悄悄地创建了串行队列(在dispatch_queue_create中传递NULL等于DISPATCH_QUEUE_SERIAL)。

如果你希望创建并发队列(以获得所有多线程功能),他的代码将导致崩溃,因为突变期间的NSArray变异(addObject :)(removeObjectAtIndex :)甚至是坏访问(NSArray范围超出边界)。在这种情况下,我们应该使用barrier来确保在两个块运行时对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.

答案 4 :(得分:3)

如果你想要一些实际使用的样品,请看看我的这个问题:

How do I resolve this deadlock that happen ocassionally?

我通过确保在主线程上创建主要的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]];
}

答案 5 :(得分:2)

dispatch_sync主要用于dispatch_async块内部,以在主线程上执行某些操作(如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;
    });
});

答案 6 :(得分:0)

这是一个中间的现实例子。您有2000个要同时分析的zip文件。但是zip库不是线程安全的。因此,触及zip库的所有工作都会进入unzipQueue队列。 (示例在Ruby中,但所有调用都直接映射到C库。“apply”,例如,映射到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

答案 7 :(得分:-1)

我在异步调度内部使用了调度同步,以便将UI更改回主线程。

我的异步块只保留了一点,我知道主线程知道UI更改并将对其进行操作。通常在处理代码块中使用它,这需要花费一些CPU时间,但我仍然希望在该块中操作UI更改。在相同的块中操作UI更改是无用的,因为我认为,UI在主线程上运行。同时将它们作为辅助异步块或自我委托操作,导致UI仅在几秒钟后才看到它们并且看起来很迟。

示例块:

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 */});
         }

 });