]> git.saurik.com Git - apple/libdispatch.git/blame - man/dispatch_async.3
libdispatch-84.5.5.tar.gz
[apple/libdispatch.git] / man / dispatch_async.3
CommitLineData
0ab74447
A
1.\" Copyright (c) 2008-2009 Apple Inc. All rights reserved.
2.Dd May 1, 2009
3.Dt dispatch_async 3
4.Os Darwin
5.Sh NAME
6.Nm dispatch_async ,
7.Nm dispatch_sync
8.Nd schedule blocks for execution
9.Sh SYNOPSIS
10.Fd #include <dispatch/dispatch.h>
11.Ft void
12.Fo dispatch_async
13.Fa "dispatch_queue_t queue" "void (^block)(void)"
14.Fc
15.Ft void
16.Fo dispatch_sync
17.Fa "dispatch_queue_t queue" "void (^block)(void)"
18.Fc
19.Ft void
20.Fo dispatch_async_f
21.Fa "dispatch_queue_t queue" "void *context" "void (*function)(void *)"
22.Fc
23.Ft void
24.Fo dispatch_sync_f
25.Fa "dispatch_queue_t queue" "void *context" "void (*function)(void *)"
26.Fc
27.Sh DESCRIPTION
28The
29.Fn dispatch_async
30and
31.Fn dispatch_sync
32functions schedule blocks for concurrent execution within the
33.Xr dispatch 3
34framework. Blocks are submitted to a queue which dictates the policy for their
35execution. See
36.Xr dispatch_queue_create 3
37for more information about creating dispatch queues.
38.Pp
39These functions support efficient temporal synchronization, background
40concurrency and data-level concurrency. These same functions can also be used
41for efficient notification of the completion of asynchronous blocks (a.k.a.
42callbacks).
43.Sh TEMPORAL SYNCHRONIZATION
44Synchronization is often required when multiple threads of execution access
45shared data concurrently. The simplest form of synchronization is
46mutual-exclusion (a lock), whereby different subsystems execute concurrently
47until a shared critical section is entered. In the
48.Xr pthread 3
49family of procedures, temporal synchronization is accomplished like so:
50.Bd -literal -offset indent
51int r = pthread_mutex_lock(&my_lock);
52assert(r == 0);
53
54// critical section
55
56r = pthread_mutex_unlock(&my_lock);
57assert(r == 0);
58.Ed
59.Pp
60The
61.Fn dispatch_sync
62function may be used with a serial queue to accomplish the same style of
63synchronization. For example:
64.Bd -literal -offset indent
65dispatch_sync(my_queue, ^{
66 // critical section
67});
68.Ed
69.Pp
70In addition to providing a more concise expression of synchronization, this
71approach is less error prone as the critical section cannot be accidentally
72left without restoring the queue to a reentrant state.
73.Pp
74The
75.Fn dispatch_async
76function may be used to implement deferred critical sections when the result
77of the block is not needed locally. Deferred critical sections have the same
78synchronization properties as the above code, but are non-blocking and
79therefore more efficient to perform. For example:
80.Bd -literal
81dispatch_async(my_queue, ^{
82 // critical section
83});
84.Ed
85.Sh BACKGROUND CONCURRENCY
86.The
87.Fn dispatch_async
88function may be used to execute trivial backgound tasks on a global concurrent
89queue. For example:
90.Bd -literal
91dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
92 // background operation
93});
94.Ed
95.Pp
96This approach is an efficient replacement for
97.Xr pthread_create 3 .
98.Sh COMPLETION CALLBACKS
99Completion callbacks can be accomplished via nested calls to the
100.Fn dispatch_async
101function. It is important to remember to retain the destination queue before the
102first call to
103.Fn dispatch_async ,
104and to release that queue at the end of the completion callback to ensure the
105destination queue is not deallocated while the completion callback is pending.
106For example:
107.Bd -literal
108void
109async_read(object_t obj,
110 void *where, size_t bytes,
111 dispatch_queue_t destination_queue,
112 void (^reply_block)(ssize_t r, int err))
113{
114 // There are better ways of doing async I/O.
115 // This is just an example of nested blocks.
116
117 dispatch_retain(destination_queue);
118
119 dispatch_async(obj->queue, ^{
120 ssize_t r = read(obj->fd, where, bytes);
121 int err = errno;
122
123 dispatch_async(destination_queue, ^{
124 reply_block(r, err);
125 });
126 dispatch_release(destination_queue);
127 });
128}
129.Ed
130.Sh RECURSIVE LOCKS
131While
132.Fn dispatch_sync
133can replace a lock, it cannot replace a recursive lock. Unlike locks, queues
134support both asynchronous and synchrnous operations, and those operations are
135ordered by definition. A recursive call to
136.Fn dispatch_sync
137causes a simple deadlock as the currently executing block waits for the next
138block to complete, but the next block will not start until the currently
139running block completes.
140.Pp
141As the dispatch framework was designed, we studied recursive locks. We found
142that the vast majority of recursive locks are deployed retroactively when
143ill-defined lock hierarchies are discovered. As a consequence, the adoption of
144recursive locks often mutates obvious bugs into obscure ones. This study also
145revealed an insight: if reentrancy is unavoidable, then reader/writer locks are
146preferable to recursive locks. Disciplined use of reader/writer locks enable
147reentrancy only when reentrancy is safe (the "read" side of the lock).
148.Pp
149Nevertheless, if it is absolutely necessary, what follows is an imperfect way of
150implementing recursive locks using the dispatch framework:
151.Bd -literal
152void
153sloppy_lock(object_t object, void (^block)(void))
154{
155 if (object->owner == pthread_self()) {
156 return block();
157 }
158 dispatch_sync(object->queue, ^{
159 object->owner = pthread_self();
160 block();
161 object->owner = NULL;
162 });
163}
164.Ed
165.Pp
166The above example does not solve the case where queue A runs on thread X which
167calls
168.Fn dispatch_sync
169against queue B which runs on thread Y which recursively calls
170.Fn dispatch_sync
171against queue A, which deadlocks both examples. This is bug-for-bug compatible
172with nontrivial pthread usage. In fact, nontrivial reentrancy is impossible to
173support in recursive locks once the ultimate level of reentrancy is deployed
174(IPC or RPC).
175.Sh IMPLIED REFERENCES
176Synchronous functions within the dispatch framework hold an implied reference
177on the target queue. In other words, the synchronous function borrows the
178reference of the calling function (this is valid because the calling function
179is blocked waiting for the result of the synchronous function, and therefore
180cannot modify the reference count of the target queue until after the
181synchronous function has returned).
182For example:
183.Bd -literal
184queue = dispatch_queue_create("com.example.queue", NULL);
185assert(queue);
186dispatch_sync(queue, ^{
187 do_something();
188 //dispatch_release(queue); // NOT SAFE -- dispatch_sync() is still using 'queue'
189});
190dispatch_release(queue); // SAFELY balanced outside of the block provided to dispatch_sync()
191.Ed
192.Pp
193This is in contrast to asynchronous functions which must retain both the block
194and target queue for the duration of the asynchronous operation (as the calling
195function may immediately release its interest in these objects).
196.Sh FUNDAMENTALS
197Conceptually,
198.Fn dispatch_sync
199is a convenient wrapper around
200.Fn dispatch_async
201with the addition of a semaphore to wait for completion of the block, and a
202wrapper around the block to signal its completion. See
203.Xr dispatch_semaphore_create 3
204for more information about dispatch semaphores. The actual implementation of the
205.Fn dispatch_sync
206function may be optimized and differ from the above description.
207.Pp
208The
209.Fn dispatch_async
210function is a wrapper around
211.Fn dispatch_async_f .
212The application-defined
213.Fa context
214parameter is passed to the
215.Fa function
216when it is invoked on the target
217.Fa queue .
218.Pp
219The
220.Fn dispatch_sync
221function is a wrapper around
222.Fn dispatch_sync_f .
223The application-defined
224.Fa context
225parameter is passed to the
226.Fa function
227when it is invoked on the target
228.Fa queue .
229.Pp
230.Sh SEE ALSO
231.Xr dispatch_once 3 ,
232.Xr dispatch_queue_create 3 ,
233.Xr dispatch_semaphore_create 3 ,
234.Xr dispatch_apply 3