Пример блока:

кто-нибудь объяснить с очень ясными случаями использования, какова цельdispatch_sync вGCD это для? Я не могу понять, где и почему я должен был бы использовать это.

Спасибо!

Ответы на вопрос(8)

Решение Вопроса

Одним из примеров этого является шаблон, в котором вы используете очередь отправки вместо блокировок для синхронизации. Например, предположим, что у вас есть общий NSMutableArrayaс доступом, опосредованным очередью отправки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
        }
});
 David Gelhar06 янв. 2011 г., 02:20
@kperryua - извините, если пример не был понятен - идея в том, что отдельный поток будет выполнять несколько dispatch_async для очереди
 kperryua05 янв. 2011 г., 20:57
Я +1 это, так как это технически правильно, хотя я не особо ценюdispatch_async с последующимdispatch_sync в той же очереди. Однако этот же шаблон полезен, когда вы хотите создать несколько параллельных заданий в другой очереди, а затем ожидать их всех.
 Rasputin Jones05 янв. 2011 г., 21:56
Благодарю. Это начинает иметь смысл. Что делать, если я хочу запустить несколько параллельных потоков, используя dispatch_apply, которые обращаются к одному ресурсу с взаимным исключением. Как мне сделать это с GCD? Единственный способ состоит в том, чтобы использовать dispatch_async с последовательной очередью в моем dispatch_apply? Есть ли способ использовать dispatch_sync?
 kperryua06 янв. 2011 г., 07:01
@ Дэвид Гелхар - Нет проблем. Просто упоминать о тех, кто приходит посмотреть.
 Brad Larson♦06 янв. 2011 г., 19:42
Мне также нравится думать, что это похоже на использование-performSelector:onThread:withObject:waitUntilDone: или жеperformSelectorOnMainThread:withObject:waitUntilDone: и настройкаwaitUntilDone ДА.

выполнения некоторых операций в основном потоке (например, обновление пользовательского интерфейса).

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

са.

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

работает так же, как

pthread_mutex_lock(&lock);
//access shared resource
pthread_mutex_unlock(&lock);
 Parag Bafna29 дек. 2014 г., 08:26
Это верно для последовательной очереди, но для параллельной очереди мы должны использовать dispatch_barrier_async для операции записи и dispatch_sync для операции чтения.

которые вы хотите анализировать параллельно. Но библиотека 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
 Matt Melton09 июл. 2012 г., 16:00
Используйте псевдокод, если хотите что-то объяснить. Ruby и др. Слишком специфичны и высокого уровня.

Сначала пойми своего брата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

Теперь, скажем, вы хотите сделать что-то наРАЗНЫЕ нить и все же ждать, как будто и убедиться, что вещи сделаныпоследовательно.

Есть много причин для этого. Например, обновление пользовательского интерфейса выполняется в основном потоке.

Вот где вы используетеdispatch_sync

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

Здесь вы получили//Do something //Do something else а также//Do More stuff сделано последовательно, хотя//Do something else сделано в другой теме.

Обычно, когда люди используют разные потоки, цель состоит в том, чтобы что-то могло быть выполнено без ожидания. Скажем, вы хотите загрузить большой объем данных, но хотите, чтобы интерфейс был гладким.

Следовательно, dispatch_sync используется редко. Но это там. Я лично никогда не использовал это. Почему бы не попросить пример кода или проекта, который использует dispatch_sync.

 Aurelien Porte21 окт. 2013 г., 20:10
Как новичок в GCD, я нашел это предложение вводящим в заблуждение: «Вы используете dispatch_async для создания нового потока». Из того, что я до сих пор понимал в GCD, вызов dispatch_async не обязательно создает новый поток. Система будет обрабатывать создание потока или атрибуцию для каждой поставленной в очередь задачи.
 guptron07 июл. 2013 г., 20:46
Это был отличный ответ для меня, спасибо. Пример использованияdispatch_sync находится внутри другого асинхронного процесса для использования в качестве обратного вызова. Например, NSManagedObjectContext Core DataperformBlock Метод может использовать его в конце блока в качестве обратного вызова.
 user495105 нояб. 2013 г., 11:08
На самом деле я использую это много сейчас. Я могу выполнить код в фоновом потоке и dispatch_sync для основного потока.
 darkheartfelt14 июн. 2014 г., 22:43
Это здорово - действительно понять это сейчас. Спасибо!
 Ixx17 янв. 2015 г., 19:45
Помимо очевидной маленькой ошибки, указанной в комментариях, это объяснение очень ясное и полезное, спасибо!

посмотрите на мой вопрос:

Как мне разрешить этот тупик, который иногда случается?

Я решаю это, гарантируя, что мой главный 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_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 */});
         }

 });

Дэвид Гелхар оставил недосказанным, что его пример будет работать только потому, что он тихо создал последовательную очередь (передал NULL в dispatch_queue_create, что равно DISPATCH_QUEUE_SERIAL).

Если вы хотите создать параллельную очередь (чтобы получить всю мощь многопоточности), его код приведет к сбою из-за мутации NSArray (addObject :) во время мутации (removeObjectAtIndex :) или даже из-за плохого доступа (диапазон 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.

Ваш ответ на вопрос