¿Alguien puede explicar con muy claros casos de uso cuál es el propósito de dispatch_sync en GCD es para? Yo no puedo entender dónde y por qué yo tendría que usar esto.

Gracias!

8 Comentarios

  1. 77

    Utiliza cuando se desea ejecutar un bloque y esperar los resultados.

    Un ejemplo de esto es el patrón en el que usted está usando un despacho de la cola en lugar de esclusas para la sincronización. Por ejemplo, supongamos que usted tiene una compartido NSMutableArray a, con acceso mediada por el envío de la cola de q. Un subproceso de fondo podría ser anexar a la matriz (async), mientras que en primer plano hilo es tirar el primer elemento (sincrónicamente):

    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
            }
    });
    • Voy a +1 a esto, ya que es técnicamente correcta, aunque creo que no hay mucho valor en hacer una sola dispatch_async seguido por un dispatch_sync en la misma cola. Sin embargo, este mismo patrón es útil cuando se desea generar varios trabajos simultáneos en otra cola y, a continuación, espere a que todos ellos.
    • Gracias. Esto está empezando a tener sentido. Lo que si quiero empezar a varios subprocesos simultáneos utilizando dispatch_apply que el acceso a un único recurso con exclusión mutua. ¿Cómo puedo hacer esto con MCD? Es la única manera de hacerlo es utilizar un dispatch_async con la serie de cola dentro de mi dispatch_apply? Es allí una manera de utilizar dispatch_sync?
    • lo siento si el ejemplo no era clara la idea es que un subproceso independiente estaría haciendo múltiples dispatch_async a la cola
    • Gelhar – No hay problema. Sólo hacer mención de otros que vienen buscando.
    • Jones – que todavía Es posible el uso regular de un mutex lock en un MCD de cola, pero también puede lograr esto con dispatch_sync: crear una nueva cola dedicada a su recurso compartido. Dentro del bloque de pasar a dispatch_apply, uso dispatch_sync con esa cola y el acceso al recurso compartido dentro de ese bloque. Usted puede utilizar __block variables si necesita obtener datos de vuelta de ese bloque (siempre y cuando seas cuidadoso de no permitir la pérdida de recursos con ella).
    • También me gusta pensar en él como siendo similar a la utilización de -performSelector:onThread:withObject:waitUntilDone: o performSelectorOnMainThread:withObject:waitUntilDone: y configuración de waitUntilDone para SÍ.
    • Gracias a todos. Mucho más claro ahora.
    • Brad es importante tener en cuenta que aunque performSelector:onThread:withObject:waitUntilDone: es similar no es un reemplazo. No hay ninguna garantía en performSelector: que su método se ejecute todos juntos. Es mejor usar dispatch_sync para garantizar que un dispatch_async hilo no será ejecutado entre su código.
    • ¿hay algún momento que un dispatch_sync no puede hacer lo que un bloqueo que se puede hacer? Si es así, donde?

  2. 77

    Entender primero su hermano dispatch_async

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

    Utilizar dispatch_async para crear un nuevo hilo. Cuando haces eso, el subproceso actual no va a parar. Eso significa que //Do More Stuff puede ser ejecutado antes de //Do something else acabado

    ¿Qué ocurre si usted desea que el subproceso actual a parar?

    No envío del uso de en todos los. Sólo tiene que escribir el código normalmente

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

    Ahora, digamos que usted quiere hacer algo en un DIFERENTES hilo y, sin embargo, espera a que si y garantizar que los productos alimenticios se realizan consecutivamente.

    Hay muchos motivos para ello. Interfaz de usuario de actualización, por ejemplo, se hace en el hilo principal.

    Que es donde el uso de dispatch_sync

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

    Aquí tienes //Do something //Do something else y //Do More stuff hecho consecutivamente aunque //Do something else se realiza en un subproceso diferente.

    Generalmente, cuando la gente usa diferentes hilo, el propósito es que algo puede ejecutar sin necesidad de esperar. Digamos que usted desea descargar gran cantidad de datos, pero desea mantener la interfaz de usuario fluida.

    Por lo tanto, dispatch_sync rara vez se utiliza. Pero ahí está. Yo, personalmente, nunca usado. ¿Por qué no pide el código de ejemplo o proyecto que hace uso de dispatch_sync.

    • Esta fue una gran respuesta para mí, gracias. Un ejemplo del uso de dispatch_sync es desde dentro de otra asynch proceso para utilizar como una devolución de llamada. Por ejemplo, los Datos de los núcleos de la NSManagedObjectContext performBlock método que se puede utilizar al final de la cuadra como una devolución de llamada.
    • Como un MCD principiante, me encontré con esta frase engañosa:»Se puede utilizar dispatch_async para crear un nuevo hilo». De lo que he entendido de MCD tan lejos, llamando dispatch_async no necesariamente crea un nuevo hilo. El sistema de rosca de la manija de la creación o atribución a cada uno en la cola de tareas, supongo.
    • En realidad, yo utiliza mucho en esto ahora. Puedo ejecutar código en el subproceso de fondo y dispatch_sync al hilo principal.
    • Esto es GENIAL – realmente lo entiendo ahora. Gracias!
    • //Hacer algo dispatch_sync(cola, ^{ //Hacer algo }); //Hacer Más Cosas Aquí tienes //Hacer algo //Hacer algo más y /o Hacer Más cosas por hacer, consecutivamente, aunque //Hacer algo se hace en un subproceso diferente. Esto no es cierto, //Hacer algo más no necesariamente se ejecutan en diferentes hilo, el sistema decidirá si va a ejecutar en el mismo hilo o un subproceso diferente.
    • Además de un evidente error poco, se indica en los comentarios, esta explicación es muy clara y útil, gracias!
    • Para crear una cola (de serie por ejemplo), el uso de dispatch_queue_t queue = dispatch_create_queue("com.mydomain.myname.somequeuename", DISPATCH_QUEUE_SERIAL); y, a continuación, se puede utilizar para la sincronización de cosas como: dispatch_async(queue, ^{ /* some code for the block */ });.
    • Y la regla básica sigo: si la lectura de una variable, utilice dispatch_sync(): __block NSUInteger myValue; dispatch_sync(queue, ^{ myValue = someValueSynced; });. Si la escritura, uso de dispatch_async() y llame a una actualización: dispatch_async(queue, ^{ someValueSynced = something; dispatch_async(dispatch_get_main_queue(), ^{ /* update UI, something like tableView reloadData or so */ }); }); (los métodos que la lectura y actualización de la interfaz de usuario deben ser sincronizados utilizando dispatch_sync(), por lo que este debe ser seguro para subprocesos).
    • y como para que el pequeño error, me pregunto cómo se puede lograr algo de forma asíncrona, sin crear un nuevo hilo?

  3. 25

    dispatch_sync es semánticamente equivalente a una tradicional mutex lock.

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

    funciona de la misma como

    pthread_mutex_lock(&lock);
    //access shared resource
    pthread_mutex_unlock(&lock);
    • Esto es cierto para la serie de cola, pero para concurrente cola debemos utilizar dispatch_barrier_async para la operación de escritura y dispatch_sync para la operación de lectura.
  4. 4

    David Gelhar izquierda dice que su ejemplo de trabajo sólo porque él ha creado silenciosamente serie de cola (se pasa NULL en dispatch_queue_create lo que es igual a DISPATCH_QUEUE_SERIAL).

    Si usted desea crear concurrente de la cola (que ganar todos multithread de poder), su código conducirá a un accidente a causa de NSArray mutación (addObject:) durante mutación (removeObjectAtIndex:) o incluso la mala acceso (NSArray gama más allá de los límites). En ese caso se debe usar una barrera para garantizar el acceso exclusivo a la NSArray, mientras que los dos bloques. No sólo excluyen a todos los demás, escribe a la NSArray mientras se ejecuta, sino que también excluye a todos los demás lee, haciendo que la modificación de seguros.

    Ejemplo para concurrente de la cola debe tener este aspecto:

    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.
  5. 3

    Si quieres ver algunos ejemplos de uso práctico vistazo a esta pregunta mía:

    ¿Cómo puedo resolver este punto muerto que ocurren ocasionalmente?

    Me resolverlo por asegurar que mi principal managedObjectContext se crea en el hilo principal. El proceso es muy rápido y no me importa esperar. No se espera significa que voy a tener que lidiar con un montón de concurency problema.

    Necesito dispatch_sync debido a que el código necesita ser hecho en el hilo principal, que es el subproceso diferente de aquel en el que el código se ejecuta.

    Así que, básicamente, si desea que el código para
    1. Proceder como de costumbre. Usted no quiere preocuparse por las condiciones de carrera. Usted desea asegurarse de que el código se completó antes de pasar.
    2. Hecho en un subproceso diferente

    uso dispatch_sync.

    Si 1 es violado, el uso de dispatch_async. Si 2 es violado escribir el código, como de costumbre.

    Hasta ahora, sólo he de hacer esto una vez, es decir, cuando algo necesita ser hecho en el hilo principal.

    Así que aquí está el código:

    +(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]];
    }
  6. 2

    dispatch_sync se utiliza principalmente en el interior de dispatch_async bloque para realizar algunas operaciones en el hilo principal(como la actualización de la interfaz de usuario).

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

    Aquí está a medio camino realista ejemplo. Tiene 2000 zip los archivos que desea analizar en paralelo. Pero el zip de la biblioteca no es thread-safe. Por lo tanto, todo el trabajo que toca el zip de la biblioteca va en el unzipQueue cola. (El ejemplo está en Ruby, pero todas las llamadas que se asignan directamente a la biblioteca de C. «aplicar», por ejemplo, los mapas de 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
    • El uso de pseudo-código, si se quiere explicar algo. Ruby, et al, son demasiado específicas y de alto nivel.
  8. -1

    He usado envío de sincronización cuando dentro de un async envío de la señal de interfaz de usuario los cambios de nuevo en el hilo principal.

    Mi async bloque aguanta solo un poco y sé que el hilo principal es consciente de la interfaz de usuario de los cambios y la acción de ellos. Generalmente se utiliza esta en un bloque de procesamiento de código que toma algo de tiempo de CPU, pero todavía quiero a la acción de interfaz de usuario los cambios desde dentro de ese bloque. Accionamiento de la interfaz de usuario los cambios en la async bloque es inútil como interfaz de usuario, creo, se ejecuta en el hilo principal. También accionamiento como secundaria async bloques, o un auto delegado, los resultados en la interfaz de usuario sólo de verlos un par de segundos más tarde y parece que la tardanza.

    Ejemplo de bloque:

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

Dejar respuesta

Please enter your comment!
Please enter your name here