NAME¶
dispatch_queue_create
,
dispatch_queue_get_label
,
dispatch_get_current_queue
,
dispatch_get_global_queue
,
dispatch_get_main_queue
,
dispatch_main
,
dispatch_set_target_queue
—
where blocks are scheduled for execution
SYNOPSIS¶
#include
<dispatch/dispatch.h>
dispatch_queue_t
dispatch_queue_create
(
const
char *label,
dispatch_queue_attr_t
attr);
const char *
dispatch_queue_get_label
(
dispatch_queue_t
queue);
dispatch_queue_t
dispatch_get_current_queue
(
void);
dispatch_queue_t
dispatch_get_global_queue
(
long
priority,
unsigned long flags);
dispatch_queue_t
dispatch_get_main_queue
(
void);
void
dispatch_main
(
void);
void
dispatch_set_target_queue
(
dispatch_object_t
object,
dispatch_queue_t target);
DESCRIPTION¶
Queues are the fundamental mechanism for scheduling blocks for execution within
the
dispatch(3) framework.
All blocks submitted to dispatch queues are dequeued in FIFO order. By default,
queues created with
dispatch_queue_create
()
wait for the previously dequeued block to complete before dequeuing the next
block. This FIFO completion behavior is sometimes simply described as a
"serial queue." Queues are not bound to any specific thread of
execution and blocks submitted to independent queues may execute concurrently.
Queues, like all dispatch objects, are reference counted and newly created
queues have a reference count of one.
The optional
label argument is used to describe
the purpose of the queue and is useful during debugging and performance
analysis. By convention, clients should pass a reverse DNS style label. If a
label is provided, it is copied. If a label is not provided, then
dispatch_queue_get_label
() returns an empty
C string. For example:
my_queue = dispatch_queue_create("com.example.subsystem.taskXYZ", NULL);
The
attr argument is reserved for future use
and must be NULL.
Queues may be temporarily suspended and resumed with the functions
dispatch_suspend
() and
dispatch_resume
() respectively. Suspension
is checked prior to block execution and is
not
preemptive.
MAIN QUEUE¶
The dispatch framework provides a default serial queue for the application to
use. This queue is accessed via
dispatch_get_main_queue
(). Programs must
call
dispatch_main
() at the end of
main
() in order to process blocks submitted
to the main queue. (See the compatibility section for exceptions.)
GLOBAL CONCURRENT QUEUES¶
Unlike the main queue or queues allocated with
dispatch_queue_create
(), the global
concurrent queues schedule blocks as soon as threads become available
(non-FIFO completion order). The global concurrent queues represent three
priority bands:
- DISPATCH_QUEUE_PRIORITY_HIGH
- DISPATCH_QUEUE_PRIORITY_DEFAULT
- DISPATCH_QUEUE_PRIORITY_LOW
Blocks submitted to the high priority global queue will be invoked before those
submitted to the default or low priority global queues. Blocks submitted to
the low priority global queue will only be invoked if no blocks are pending on
the default or high priority queues.
RETURN VALUES¶
The
dispatch_queue_create
() function returns
NULL on failure.
The
dispatch_queue_get_label
() function
always returns a valid C string. An empty C string is returned if the
label was NULL creation time.
The
dispatch_get_main_queue
() function
returns the default main queue.
The
dispatch_get_current_queue
() function
always returns a valid queue. When called from within a block submitted to a
dispatch queue, that queue will be returned. If this function is called from
the main thread before
dispatch_main
() is
called, then the result of
dispatch_get_main_queue
() is returned.
Otherwise, the result of
dispatch_get_global_queue
(
DISPATCH_QUEUE_PRIORITY_DEFAULT,
0); will be returned in all other cases.
The
dispatch_main
() function never returns.
TARGET QUEUE¶
The
dispatch_set_target_queue
() function
updates the target queue of the given dispatch object. The target queue of an
object is responsible for processing the object. Currently only dispatch
queues and dispatch sources are supported by this function. The result of
using
dispatch_set_target_queue
() with any
other dispatch object type is undefined.
The new target queue is retained by the given object before the previous target
queue is released. The new target queue will take effect between block
executions, but not in the middle of any existing block executions
(non-preemptive).
The priority of a dispatch queue is inherited by its target queue. In order to
change the priority of a queue created with
dispatch_queue_create
(), use the
dispatch_get_global_queue
() function to
obtain a target queue of the desired priority. The
flags argument is reserved for future use and
must be zero. Passing any value other than zero may result in a
NULL return value.
The target queue of a dispatch source specifies where its event handler and
cancellation handler blocks will be submitted. See
dispatch_source_create(3) for more information
about dispatch sources.
The result of passing the main queue or a global concurrent queue to the first
argument of
dispatch_set_target_queue
() is
undefined.
Directly or indirectly setting the target queue of a dispatch queue to itself is
undefined.
CAVEATS¶
Code cannot make any assumptions about the queue returned by
dispatch_get_current_queue
(). The returned
queue may have arbitrary policies that may surprise code that tries to
schedule work with the queue. The list of policies includes, but is not
limited to, queue width (i.e. serial vs. concurrent), scheduling priority,
security credential or filesystem configuration. Therefore,
dispatch_get_current_queue
()
MUST only be used for identity tests or
debugging.
COMPATIBILITY¶
Cocoa applications need not call
dispatch_main
(). Blocks submitted to the
main queue will be executed as part of the "common modes" of the
application's main NSRunLoop or CFRunLoop. However, blocks submitted to the
main queue in applications using
dispatch_main
() are not guaranteed to
execute on the main thread.
The dispatch framework is a pure C level API. As a result, it does not catch
exceptions generated by higher level languages such as Objective-C or C++.
Applications
MUST catch all exceptions before
returning from a block submitted to a dispatch queue; otherwise the internal
data structures of the dispatch framework will be left in an inconsistent
state.
The dispatch framework manages the relationship between dispatch queues and
threads of execution. As a result, applications
MUST
NOT delete or mutate objects that they did not create. The following
interfaces
MUST NOT be called by blocks submitted
to a dispatch queue:
pthread_cancel
()
pthread_detach
()
pthread_join
()
pthread_kill
()
pthread_exit
()
Applications
MAY call the following interfaces from
a block submitted to a dispatch queue if and only if they restore the thread
to its original state before returning:
pthread_setcancelstate
()
pthread_setcanceltype
()
pthread_setschedparam
()
pthread_sigmask
()
pthread_setugid_np
()
pthread_chdir
()
pthread_fchdir
()
Applications
MUST NOT rely on the following
interfaces returning predictable results between invocations of blocks
submitted to a dispatch queue:
pthread_self
()
pthread_getschedparam
()
pthread_get_stacksize_np
()
pthread_get_stackaddr_np
()
pthread_mach_thread_np
()
pthread_from_mach_thread_np
()
While the result of
pthread_self
() may change
between invocations of blocks, the value will not change during the execution
of any single block. Because the underlying thread may change beteween block
invocations on a single queue, using per-thread data as an out-of-band return
value is error prone. In other words, the result of calling
pthread_setspecific
() and
pthread_getspecific
() is well defined
within a signle block, but not across multiple blocks. Also, one cannot make
any assumptions about when the destructor passed to
pthread_key_create
() is called. The
destructor may be called between the invocation of blocks on the same queue,
or during the idle state of a process.
The following example code correctly handles per-thread return values:
__block int r;
__block int e;
dispatch_sync(queue, ^{
r = kill(1, 0);
// Copy the per-thread return value to the callee thread
e = errno;
});
printf("kill(1,0) returned %d and errno %d0, r, e);
Note that in the above example
errno is a
per-thread variable and must be copied out explicitly as the block may be
invoked on different thread of execution than the caller. Another example of
per-thread data that would need to be copied is the use of
getpwnam
() instead of
getpwnam_r
().
As an optimization,
dispatch_sync
() invokes
the block on the current thread when possible. In this case, the thread
specific data such as
errno may persist from
the block until back to the caller. Great care should be taken not to
accidentally rely on this side-effect.
SEE ALSO¶
dispatch(3),
dispatch_async(3),
dispatch_object(3),
dispatch_source_create(3)