dispatch_async vs dispatch_sync执行顺序

时间:2020-12-16 08:06:47

I have a serial dispatch queue created with:

我有一个创建的串行调度队列:

dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL);

I want to use this serial queue to ensure thread safety for class access, while automatically doing work asynchronously that doesn't need to return to the calling thread.

我想使用这个串行队列来确保类访问的线程安全性,同时自动异步工作,不需要返回调用线程。

- (void)addObjectToQueue:(id)object
{
    dispatch_async(serialQueue, ^{
        // process object and add to queue
    }); 
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(serialQueue, ^{
        // work out return value
    });
    return returnValue;
} 

If I call the addObjectToQueue: method, then immediately call the isObjectInQueue: method, are they guaranteed to be executed in the same order, or will/could the isObjectInQueue execute first?

如果我调用addObjectToQueue:方法,然后立即调用isObjectInQueue:方法,它们是否保证以相同的顺序执行,或者is / In可以先执行isObjectInQueue?

In other words, does dispatch_async perform exactly the same as dispatch_sync (scheduling the block immediately) except that it doesn't block the calling thread?

换句话说,dispatch_async执行与dispatch_sync完全相同(立即调度块),除了它不阻塞调用线程?

I have seen similar questions with answers going both ways, so I am looking for a definitive answer, preferably backed with Apple documentation.

我已经看到类似的问题,答案是双向的,所以我正在寻找一个明确的答案,最好用Apple文档支持。

2 个解决方案

#1


13  

Are they guaranteed to be executed in the same order?

它们是否保证以相同的顺序执行?

Yes.

Will / could the isObjectInQueue execute first?

是否可以首先执行isObjectInQueue?

Yes.

The reason for the yes to both answers is you should consider threading. Which is presumably why you are using the serial queue in the first place. You are making access to that queue thread safe.

两个答案都是肯定的原因是你应该考虑线程。这可能是您首先使用串行队列的原因。您正在访问该队列线程安全。

Basically, the blocks will execute in the order in which they are put on the serial queue. That is 100% guaranteed. However, if multiple threads are hammering away at this then one thread may get in first to read something from the queue before another has had chance to add it.

基本上,块将按照它们放在串行队列上的顺序执行。这是100%保证。但是,如果多个线程正在锤击,那么在另一个线程有机会添加它之前,一个线程可能首先进入队列中读取某些内容。

In other words, does dispatch_async perform exactly the same as dispatch_sync (scheduling the block immediately) except that it doesn't block the calling thread?

换句话说,dispatch_async执行与dispatch_sync完全相同(立即调度块),除了它不阻塞调用线程?

That's right. In both cases the block is added to the queue. It is added immediately. dispatch_sync just waits for the block to finish before returning whereas dispatch_async returns immediately.

那就对了。在这两种情况下,块都会添加到队列中。它会立即添加。 dispatch_sync在返回之前等待块完成,而dispatch_async立即返回。

#2


2  

I guess your question is, will the main thread keep running while dispatch_async is still executing the queue operation? I assume it won't, because that would deserve a explicit mention. If anything, I found this in dispatch_async.3 which suggests this is the case:

我想你的问题是,当dispatch_async仍在执行队列操作时,主线程是否会继续运行?我认为它不会,因为这值得一提。如果有的话,我在dispatch_async.3中发现了这一点,这表明情况如此:

Conceptually, dispatch_sync() is a convenient wrapper around dispatch_async() with the addition of a semaphore to wait for completion of the block, and a wrapper around the block to signal its completion.

从概念上讲,dispatch_sync()是dispatch_async()的一个方便的包装器,它增加了一个等待块完成的信号量,并在块周围有一个包装器来表示它的完成。

And indeed, if you follow the source code for dispatch_async in queue.c you'll see that the block is queued on the foreground, and only after that, execution returns to the code that called dispatch_async. Therefore if the queue is serial, dispatch_async followed by a dispatch_sync from the same thread will queue the blocks in order.

实际上,如果您遵循queue.c中dispatch_async的源代码,您将看到该块在前台排队,并且只有在此之后,执行才会返回到调用dispatch_async的代码。因此,如果队列是串行的,则dispatch_async后跟来自同一线程的dispatch_sync将按顺序排列块。

Because dispatch_sync will block until the block (and all blocks before in a serial queue) are done executing, then your code would be right. isObjectInQueue: will correctly report if the object added before is in the queue.

因为dispatch_sync将阻塞直到块(以及串行队列中的所有块)完成执行,那么您的代码将是正确的。 isObjectInQueue:将正确报告之前添加的对象是否在队列中。

edit: on a multithreaded environment I would write the code above as:

编辑:在多线程环境中,我会将上面的代码编写为:

- (void)addObjectToQueue:(id)object
{
    dispatch_barrier_async(_queue, ^{
        // process object and add to queue
    });
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(_queue, ^{
        // work out return value
    });
    return returnValue;
} 

because execution of each method can be deferred at any point in favor of another thread.

因为每个方法的执行都可以在任何时候推迟,以支持另一个线程。

#1


13  

Are they guaranteed to be executed in the same order?

它们是否保证以相同的顺序执行?

Yes.

Will / could the isObjectInQueue execute first?

是否可以首先执行isObjectInQueue?

Yes.

The reason for the yes to both answers is you should consider threading. Which is presumably why you are using the serial queue in the first place. You are making access to that queue thread safe.

两个答案都是肯定的原因是你应该考虑线程。这可能是您首先使用串行队列的原因。您正在访问该队列线程安全。

Basically, the blocks will execute in the order in which they are put on the serial queue. That is 100% guaranteed. However, if multiple threads are hammering away at this then one thread may get in first to read something from the queue before another has had chance to add it.

基本上,块将按照它们放在串行队列上的顺序执行。这是100%保证。但是,如果多个线程正在锤击,那么在另一个线程有机会添加它之前,一个线程可能首先进入队列中读取某些内容。

In other words, does dispatch_async perform exactly the same as dispatch_sync (scheduling the block immediately) except that it doesn't block the calling thread?

换句话说,dispatch_async执行与dispatch_sync完全相同(立即调度块),除了它不阻塞调用线程?

That's right. In both cases the block is added to the queue. It is added immediately. dispatch_sync just waits for the block to finish before returning whereas dispatch_async returns immediately.

那就对了。在这两种情况下,块都会添加到队列中。它会立即添加。 dispatch_sync在返回之前等待块完成,而dispatch_async立即返回。

#2


2  

I guess your question is, will the main thread keep running while dispatch_async is still executing the queue operation? I assume it won't, because that would deserve a explicit mention. If anything, I found this in dispatch_async.3 which suggests this is the case:

我想你的问题是,当dispatch_async仍在执行队列操作时,主线程是否会继续运行?我认为它不会,因为这值得一提。如果有的话,我在dispatch_async.3中发现了这一点,这表明情况如此:

Conceptually, dispatch_sync() is a convenient wrapper around dispatch_async() with the addition of a semaphore to wait for completion of the block, and a wrapper around the block to signal its completion.

从概念上讲,dispatch_sync()是dispatch_async()的一个方便的包装器,它增加了一个等待块完成的信号量,并在块周围有一个包装器来表示它的完成。

And indeed, if you follow the source code for dispatch_async in queue.c you'll see that the block is queued on the foreground, and only after that, execution returns to the code that called dispatch_async. Therefore if the queue is serial, dispatch_async followed by a dispatch_sync from the same thread will queue the blocks in order.

实际上,如果您遵循queue.c中dispatch_async的源代码,您将看到该块在前台排队,并且只有在此之后,执行才会返回到调用dispatch_async的代码。因此,如果队列是串行的,则dispatch_async后跟来自同一线程的dispatch_sync将按顺序排列块。

Because dispatch_sync will block until the block (and all blocks before in a serial queue) are done executing, then your code would be right. isObjectInQueue: will correctly report if the object added before is in the queue.

因为dispatch_sync将阻塞直到块(以及串行队列中的所有块)完成执行,那么您的代码将是正确的。 isObjectInQueue:将正确报告之前添加的对象是否在队列中。

edit: on a multithreaded environment I would write the code above as:

编辑:在多线程环境中,我会将上面的代码编写为:

- (void)addObjectToQueue:(id)object
{
    dispatch_barrier_async(_queue, ^{
        // process object and add to queue
    });
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(_queue, ^{
        // work out return value
    });
    return returnValue;
} 

because execution of each method can be deferred at any point in favor of another thread.

因为每个方法的执行都可以在任何时候推迟,以支持另一个线程。