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)

Darwin                                             May 1, 2009                                 dispatch_async(3)