using dispatch_sync in Grand Central Dispatch

前端 未结 8 2081
孤城傲影
孤城傲影 2020-11-30 17:25

Can anyone explain with really clear use cases what the purpose of dispatch_sync in GCD is for? I can\'t understand where and why I would have to u

相关标签:
8条回答
  • 2020-11-30 17:34

    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;
        });
    });
    
    0 讨论(0)
  • 2020-11-30 17:41

    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
    
    0 讨论(0)
  • 2020-11-30 17:44

    First understand its brother dispatch_async

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

    You use dispatch_async to create a new thread. When you do that, the current thread will not stop. That means //Do More Stuff may be executed before //Do something else finish

    What happens if you want the current thread to stop?

    You do not use dispatch at all. Just write the code normally

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

    Now, say you want to do something on a DIFFERENT thread and yet wait as if and ensure that stuffs are done consecutively.

    There are many reason to do this. UI update, for example, is done on main thread.

    That's where you use dispatch_sync

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

    Here you got //Do something //Do something else and //Do More stuff done consecutively even though //Do something else is done on a different thread.

    Usually, when people use different thread, the whole purpose is so that something can get executed without waiting. Say you want to download large amount of data but you want to keep the UI smooth.

    Hence, dispatch_sync is rarely used. But it's there. I personally never used that. Why not ask for some sample code or project that does use dispatch_sync.

    0 讨论(0)
  • 2020-11-30 17:45

    You use it when you want to execute a block and wait for the results.

    One example of this is the pattern where you're using a dispatch queue instead of locks for synchronization. For example, assume you have a shared NSMutableArray a, with access mediated by dispatch queue q. A background thread might be appending to the array (async), while your foreground thread is pulling the first item off (synchronously):

    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
            }
    });
    
    0 讨论(0)
  • 2020-11-30 17:45

    dispatch_sync is semantically equivalent to a traditional mutex lock.

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

    works the same as

    pthread_mutex_lock(&lock);
    //access shared resource
    pthread_mutex_unlock(&lock);
    
    0 讨论(0)
  • 2020-11-30 17:47

    If you want some samples of practical use look at this question of mine:

    How do I resolve this deadlock that happen ocassionally?

    I solve it by ensuring that my main managedObjectContext is created on the main thread. The process is very fast and I do not mind waiting. Not waiting means I will have to deal with a lot of concurency issue.

    I need dispatch_sync because some code need to be done on main thread, which is the different thread than the one where to code is being executed.

    So basically if you want the code to 1. Proceed like usual. You don't want to worry about race conditions. You want to ensure that the code is completed before moving on. 2. Done on a different thread

    use dispatch_sync.

    If 1 is violated, use dispatch_async. If 2 is violated just write the code like usual.

    So far, I only do this once, namely when something need to be done on main thread.

    So here's the code:

    +(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]];
    }
    
    0 讨论(0)
提交回复
热议问题