Provided by: libdispatch-dev_0~svn197-3.3ubuntu2_amd64 bug

NAME

     dispatch_async, dispatch_sync — schedule blocks for execution

SYNOPSIS

     #include <dispatch/dispatch.h>

     void
     dispatch_async(dispatch_queue_t queue, void (^block)(void));

     void
     dispatch_sync(dispatch_queue_t queue, void (^block)(void));

     void
     dispatch_async_f(dispatch_queue_t queue, void *context, void (*function)(void *));

     void
     dispatch_sync_f(dispatch_queue_t queue, void *context, void (*function)(void *));

DESCRIPTION

     The dispatch_async() and dispatch_sync() functions schedule blocks for concurrent execution
     within the dispatch(3) framework. Blocks are submitted to a queue which dictates the policy
     for their execution. See dispatch_queue_create(3) for more information about creating
     dispatch queues.

     These functions support efficient temporal synchronization, background concurrency and data-
     level concurrency. These same functions can also be used for efficient notification of the
     completion of asynchronous blocks (a.k.a.  callbacks).

TEMPORAL SYNCHRONIZATION

     Synchronization is often required when multiple threads of execution access shared data
     concurrently. The simplest form of synchronization is mutual-exclusion (a lock), whereby
     different subsystems execute concurrently until a shared critical section is entered. In the
     pthread(3) family of procedures, temporal synchronization is accomplished like so:

           int r = pthread_mutex_lock(&my_lock);
           assert(r == 0);

           // critical section

           r = pthread_mutex_unlock(&my_lock);
           assert(r == 0);

     The dispatch_sync() function may be used with a serial queue to accomplish the same style of
     synchronization. For example:

           dispatch_sync(my_queue, ^{
                   // critical section
           });

     In addition to providing a more concise expression of synchronization, this approach is less
     error prone as the critical section cannot be accidentally left without restoring the queue
     to a reentrant state.

     The dispatch_async() function may be used to implement deferred critical sections when the
     result of the block is not needed locally. Deferred critical sections have the same
     synchronization properties as the above code, but are non-blocking and therefore more
     efficient to perform. For example:

     dispatch_async(my_queue, ^{
             // critical section
     });

BACKGROUND CONCURRENCY

     dispatch_async() function may be used to execute trivial backgound tasks on a global
     concurrent queue. For example:

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
             // background operation
     });

     This approach is an efficient replacement for pthread_create(3).

COMPLETION CALLBACKS

     Completion callbacks can be accomplished via nested calls to the dispatch_async() function.
     It is important to remember to retain the destination queue before the first call to
     dispatch_async(), and to release that queue at the end of the completion callback to ensure
     the destination queue is not deallocated while the completion callback is pending.  For
     example:

     void
     async_read(object_t obj,
             void *where, size_t bytes,
             dispatch_queue_t destination_queue,
             void (^reply_block)(ssize_t r, int err))
     {
             // There are better ways of doing async I/O.
             // This is just an example of nested blocks.

             dispatch_retain(destination_queue);

             dispatch_async(obj->queue, ^{
                     ssize_t r = read(obj->fd, where, bytes);
                     int err = errno;

                     dispatch_async(destination_queue, ^{
                             reply_block(r, err);
                     });
                     dispatch_release(destination_queue);
             });
     }

RECURSIVE LOCKS

     While dispatch_sync() can replace a lock, it cannot replace a recursive lock. Unlike locks,
     queues support both asynchronous and synchronous operations, and those operations are
     ordered by definition. A recursive call to dispatch_sync() causes a simple deadlock as the
     currently executing block waits for the next block to complete, but the next block will not
     start until the currently running block completes.

     As the dispatch framework was designed, we studied recursive locks. We found that the vast
     majority of recursive locks are deployed retroactively when ill-defined lock hierarchies are
     discovered. As a consequence, the adoption of recursive locks often mutates obvious bugs
     into obscure ones. This study also revealed an insight: if reentrancy is unavoidable, then
     reader/writer locks are preferable to recursive locks. Disciplined use of reader/writer
     locks enable reentrancy only when reentrancy is safe (the "read" side of the lock).

     Nevertheless, if it is absolutely necessary, what follows is an imperfect way of
     implementing recursive locks using the dispatch framework:

     void
     sloppy_lock(object_t object, void (^block)(void))
     {
             if (object->owner == pthread_self()) {
                     return block();
             }
             dispatch_sync(object->queue, ^{
                     object->owner = pthread_self();
                     block();
                     object->owner = NULL;
             });
     }

     The above example does not solve the case where queue A runs on thread X which calls
     dispatch_sync() against queue B which runs on thread Y which recursively calls
     dispatch_sync() against queue A, which deadlocks both examples. This is bug-for-bug
     compatible with nontrivial pthread usage. In fact, nontrivial reentrancy is impossible to
     support in recursive locks once the ultimate level of reentrancy is deployed (IPC or RPC).

IMPLIED REFERENCES

     Synchronous functions within the dispatch framework hold an implied reference on the target
     queue. In other words, the synchronous function borrows the reference of the calling
     function (this is valid because the calling function is blocked waiting for the result of
     the synchronous function, and therefore cannot modify the reference count of the target
     queue until after the synchronous function has returned).  For example:

     queue = dispatch_queue_create("com.example.queue", NULL);
     assert(queue);
     dispatch_sync(queue, ^{
             do_something();
             //dispatch_release(queue); // NOT SAFE -- dispatch_sync() is still using 'queue'
     });
     dispatch_release(queue); // SAFELY balanced outside of the block provided to dispatch_sync()

     This is in contrast to asynchronous functions which must retain both the block and target
     queue for the duration of the asynchronous operation (as the calling function may
     immediately release its interest in these objects).

FUNDAMENTALS

     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. See dispatch_semaphore_create(3) for more information about
     dispatch semaphores. The actual implementation of the dispatch_sync() function may be
     optimized and differ from the above description.

     The dispatch_async() function is a wrapper around dispatch_async_f().  The application-
     defined context parameter is passed to the function when it is invoked on the target queue.

     The dispatch_sync() function is a wrapper around dispatch_sync_f().  The application-defined
     context parameter is passed to the function when it is invoked on the target queue.

SEE ALSO

     dispatch(3), dispatch_apply(3), dispatch_once(3), dispatch_queue_create(3),
     dispatch_semaphore_create(3)