annotate third_party/libuv/docs/src/guide/threads.rst @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 948de3f54cea
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
160
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
1 Threads
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
2 =======
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
3
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
4 Wait a minute? Why are we on threads? Aren't event loops supposed to be **the
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
5 way** to do *web-scale programming*? Well... no. Threads are still the medium in
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
6 which processors do their jobs. Threads are therefore mighty useful sometimes, even
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
7 though you might have to wade through various synchronization primitives.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
8
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
9 Threads are used internally to fake the asynchronous nature of all of the system
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
10 calls. libuv also uses threads to allow you, the application, to perform a task
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
11 asynchronously that is actually blocking, by spawning a thread and collecting
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
12 the result when it is done.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
13
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
14 Today there are two predominant thread libraries: the Windows threads
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
15 implementation and POSIX's :man:`pthreads(7)`. libuv's thread API is analogous to
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
16 the pthreads API and often has similar semantics.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
17
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
18 A notable aspect of libuv's thread facilities is that it is a self contained
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
19 section within libuv. Whereas other features intimately depend on the event
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
20 loop and callback principles, threads are complete agnostic, they block as
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
21 required, signal errors directly via return values, and, as shown in the
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
22 :ref:`first example <thread-create-example>`, don't even require a running
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
23 event loop.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
24
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
25 libuv's thread API is also very limited since the semantics and syntax of
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
26 threads are different on all platforms, with different levels of completeness.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
27
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
28 This chapter makes the following assumption: **There is only one event loop,
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
29 running in one thread (the main thread)**. No other thread interacts
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
30 with the event loop (except using ``uv_async_send``).
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
31
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
32 Core thread operations
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
33 ----------------------
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
34
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
35 There isn't much here, you just start a thread using ``uv_thread_create()`` and
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
36 wait for it to close using ``uv_thread_join()``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
37
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
38 .. _thread-create-example:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
39
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
40 .. rubric:: thread-create/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
41 .. literalinclude:: ../../code/thread-create/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
42 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
43 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
44 :lines: 26-36
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
45 :emphasize-lines: 3-7
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
46
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
47 .. tip::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
48
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
49 ``uv_thread_t`` is just an alias for ``pthread_t`` on Unix, but this is an
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
50 implementation detail, avoid depending on it to always be true.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
51
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
52 The second parameter is the function which will serve as the entry point for
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
53 the thread, the last parameter is a ``void *`` argument which can be used to pass
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
54 custom parameters to the thread. The function ``hare`` will now run in a separate
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
55 thread, scheduled pre-emptively by the operating system:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
56
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
57 .. rubric:: thread-create/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
58 .. literalinclude:: ../../code/thread-create/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
59 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
60 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
61 :lines: 6-14
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
62 :emphasize-lines: 2
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
63
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
64 Unlike ``pthread_join()`` which allows the target thread to pass back a value to
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
65 the calling thread using a second parameter, ``uv_thread_join()`` does not. To
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
66 send values use :ref:`inter-thread-communication`.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
67
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
68 Synchronization Primitives
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
69 --------------------------
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
70
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
71 This section is purposely spartan. This book is not about threads, so I only
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
72 catalogue any surprises in the libuv APIs here. For the rest you can look at
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
73 the :man:`pthreads(7)` man pages.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
74
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
75 Mutexes
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
76 ~~~~~~~
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
77
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
78 The mutex functions are a **direct** map to the pthread equivalents.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
79
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
80 .. rubric:: libuv mutex functions
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
81 .. code-block:: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
82
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
83 int uv_mutex_init(uv_mutex_t* handle);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
84 int uv_mutex_init_recursive(uv_mutex_t* handle);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
85 void uv_mutex_destroy(uv_mutex_t* handle);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
86 void uv_mutex_lock(uv_mutex_t* handle);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
87 int uv_mutex_trylock(uv_mutex_t* handle);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
88 void uv_mutex_unlock(uv_mutex_t* handle);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
89
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
90 The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()``
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
91 functions will return 0 on success, and an error code otherwise.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
92
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
93 If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``,
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
94 ``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
95 Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
96 than* ``EAGAIN`` or ``EBUSY``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
97
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
98 Recursive mutexes are supported, but you should not rely on them. Also, they
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
99 should not be used with ``uv_cond_t`` variables.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
100
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
101 The default BSD mutex implementation will raise an error if a thread which has
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
102 locked a mutex attempts to lock it again. For example, a construct like::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
103
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
104 uv_mutex_init(a_mutex);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
105 uv_mutex_lock(a_mutex);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
106 uv_thread_create(thread_id, entry, (void *)a_mutex);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
107 uv_mutex_lock(a_mutex);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
108 // more things here
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
109
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
110 can be used to wait until another thread initializes some stuff and then
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
111 unlocks ``a_mutex`` but will lead to your program crashing if in debug mode, or
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
112 return an error in the second call to ``uv_mutex_lock()``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
113
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
114 .. note::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
115
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
116 Mutexes on Windows are always recursive.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
117
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
118 Locks
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
119 ~~~~~
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
120
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
121 Read-write locks are a more granular access mechanism. Two readers can access
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
122 shared memory at the same time. A writer may not acquire the lock when it is
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
123 held by a reader. A reader or writer may not acquire a lock when a writer is
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
124 holding it. Read-write locks are frequently used in databases. Here is a toy
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
125 example.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
126
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
127 .. rubric:: locks/main.c - simple rwlocks
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
128 .. literalinclude:: ../../code/locks/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
129 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
130 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
131 :emphasize-lines: 13,16,27,31,42,55
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
132
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
133 Run this and observe how the readers will sometimes overlap. In case of
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
134 multiple writers, schedulers will usually give them higher priority, so if you
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
135 add two writers, you'll see that both writers tend to finish first before the
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
136 readers get a chance again.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
137
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
138 We also use barriers in the above example so that the main thread can wait for
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
139 all readers and writers to indicate they have ended.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
140
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
141 Others
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
142 ~~~~~~
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
143
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
144 libuv also supports semaphores_, `condition variables`_ and barriers_ with APIs
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
145 very similar to their pthread counterparts.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
146
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
147 .. _semaphores: https://en.wikipedia.org/wiki/Semaphore_(programming)
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
148 .. _condition variables: https://en.wikipedia.org/wiki/Monitor_(synchronization)#Condition_variables_2
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
149 .. _barriers: https://en.wikipedia.org/wiki/Barrier_(computer_science)
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
150
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
151 In addition, libuv provides a convenience function ``uv_once()``. Multiple
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
152 threads can attempt to call ``uv_once()`` with a given guard and a function
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
153 pointer, **only the first one will win, the function will be called once and
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
154 only once**::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
155
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
156 /* Initialize guard */
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
157 static uv_once_t once_only = UV_ONCE_INIT;
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
158
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
159 int i = 0;
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
160
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
161 void increment() {
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
162 i++;
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
163 }
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
164
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
165 void thread1() {
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
166 /* ... work */
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
167 uv_once(once_only, increment);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
168 }
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
169
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
170 void thread2() {
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
171 /* ... work */
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
172 uv_once(once_only, increment);
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
173 }
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
174
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
175 int main() {
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
176 /* ... spawn threads */
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
177 }
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
178
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
179 After all threads are done, ``i == 1``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
180
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
181 .. _libuv-work-queue:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
182
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
183 libuv v0.11.11 onwards also added a ``uv_key_t`` struct and api_ for
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
184 thread-local storage.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
185
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
186 .. _api: http://docs.libuv.org/en/v1.x/threading.html#thread-local-storage
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
187
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
188 libuv work queue
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
189 ----------------
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
190
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
191 ``uv_queue_work()`` is a convenience function that allows an application to run
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
192 a task in a separate thread, and have a callback that is triggered when the
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
193 task is done. A seemingly simple function, what makes ``uv_queue_work()``
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
194 tempting is that it allows potentially any third-party libraries to be used
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
195 with the event-loop paradigm. When you use event loops, it is *imperative to
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
196 make sure that no function which runs periodically in the loop thread blocks
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
197 when performing I/O or is a serious CPU hog*, because this means that the loop
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
198 slows down and events are not being handled at full capacity.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
199
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
200 However, a lot of existing code out there features blocking functions (for example
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
201 a routine which performs I/O under the hood) to be used with threads if you
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
202 want responsiveness (the classic 'one thread per client' server model), and
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
203 getting them to play with an event loop library generally involves rolling your
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
204 own system of running the task in a separate thread. libuv just provides
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
205 a convenient abstraction for this.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
206
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
207 Here is a simple example inspired by `node.js is cancer`_. We are going to
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
208 calculate fibonacci numbers, sleeping a bit along the way, but run it in
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
209 a separate thread so that the blocking and CPU bound task does not prevent the
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
210 event loop from performing other activities.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
211
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
212 .. rubric:: queue-work/main.c - lazy fibonacci
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
213 .. literalinclude:: ../../code/queue-work/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
214 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
215 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
216 :lines: 17-29
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
217
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
218 The actual task function is simple, nothing to show that it is going to be
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
219 run in a separate thread. The ``uv_work_t`` structure is the clue. You can pass
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
220 arbitrary data through it using the ``void* data`` field and use it to
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
221 communicate to and from the thread. But be sure you are using proper locks if
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
222 you are changing things while both threads may be running.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
223
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
224 The trigger is ``uv_queue_work``:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
225
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
226 .. rubric:: queue-work/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
227 .. literalinclude:: ../../code/queue-work/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
228 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
229 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
230 :lines: 31-44
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
231 :emphasize-lines: 10
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
232
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
233 The thread function will be launched in a separate thread, passed the
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
234 ``uv_work_t`` structure and once the function returns, the *after* function
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
235 will be called on the thread the event loop is running in. It will be passed
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
236 the same structure.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
237
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
238 For writing wrappers to blocking libraries, a common :ref:`pattern <baton>`
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
239 is to use a baton to exchange data.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
240
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
241 Since libuv version `0.9.4` an additional function, ``uv_cancel()``, is
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
242 available. This allows you to cancel tasks on the libuv work queue. Only tasks
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
243 that *are yet to be started* can be cancelled. If a task has *already started
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
244 executing, or it has finished executing*, ``uv_cancel()`` **will fail**.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
245
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
246 ``uv_cancel()`` is useful to cleanup pending tasks if the user requests
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
247 termination. For example, a music player may queue up multiple directories to
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
248 be scanned for audio files. If the user terminates the program, it should quit
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
249 quickly and not wait until all pending requests are run.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
250
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
251 Let's modify the fibonacci example to demonstrate ``uv_cancel()``. We first set
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
252 up a signal handler for termination.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
253
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
254 .. rubric:: queue-cancel/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
255 .. literalinclude:: ../../code/queue-cancel/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
256 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
257 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
258 :lines: 43-
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
259
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
260 When the user triggers the signal by pressing ``Ctrl+C`` we send
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
261 ``uv_cancel()`` to all the workers. ``uv_cancel()`` will return ``0`` for those that are already executing or finished.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
262
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
263 .. rubric:: queue-cancel/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
264 .. literalinclude:: ../../code/queue-cancel/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
265 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
266 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
267 :lines: 33-41
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
268 :emphasize-lines: 6
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
269
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
270 For tasks that do get cancelled successfully, the *after* function is called
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
271 with ``status`` set to ``UV_ECANCELED``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
272
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
273 .. rubric:: queue-cancel/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
274 .. literalinclude:: ../../code/queue-cancel/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
275 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
276 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
277 :lines: 28-31
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
278 :emphasize-lines: 2
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
279
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
280 ``uv_cancel()`` can also be used with ``uv_fs_t`` and ``uv_getaddrinfo_t``
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
281 requests. For the filesystem family of functions, ``uv_fs_t.errorno`` will be
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
282 set to ``UV_ECANCELED``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
283
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
284 .. TIP::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
285
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
286 A well designed program would have a way to terminate long running workers
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
287 that have already started executing. Such a worker could periodically check
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
288 for a variable that only the main process sets to signal termination.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
289
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
290 .. _inter-thread-communication:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
291
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
292 Inter-thread communication
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
293 --------------------------
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
294
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
295 Sometimes you want various threads to actually send each other messages *while*
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
296 they are running. For example you might be running some long duration task in
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
297 a separate thread (perhaps using ``uv_queue_work``) but want to notify progress
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
298 to the main thread. This is a simple example of having a download manager
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
299 informing the user of the status of running downloads.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
300
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
301 .. rubric:: progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
302 .. literalinclude:: ../../code/progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
303 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
304 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
305 :lines: 7-8,35-
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
306 :emphasize-lines: 2,11
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
307
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
308 The async thread communication works *on loops* so although any thread can be
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
309 the message sender, only threads with libuv loops can be receivers (or rather
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
310 the loop is the receiver). libuv will invoke the callback (``print_progress``)
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
311 with the async watcher whenever it receives a message.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
312
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
313 .. warning::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
314
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
315 It is important to realize that since the message send is *async*, the callback
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
316 may be invoked immediately after ``uv_async_send`` is called in another
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
317 thread, or it may be invoked after some time. libuv may also combine
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
318 multiple calls to ``uv_async_send`` and invoke your callback only once. The
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
319 only guarantee that libuv makes is -- The callback function is called *at
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
320 least once* after the call to ``uv_async_send``. If you have no pending
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
321 calls to ``uv_async_send``, the callback won't be called. If you make two
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
322 or more calls, and libuv hasn't had a chance to run the callback yet, it
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
323 *may* invoke your callback *only once* for the multiple invocations of
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
324 ``uv_async_send``. Your callback will never be called twice for just one
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
325 event.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
326
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
327 .. rubric:: progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
328 .. literalinclude:: ../../code/progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
329 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
330 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
331 :lines: 10-24
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
332 :emphasize-lines: 7-8
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
333
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
334 In the download function, we modify the progress indicator and queue the message
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
335 for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
336 non-blocking and will return immediately.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
337
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
338 .. rubric:: progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
339 .. literalinclude:: ../../code/progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
340 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
341 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
342 :lines: 31-34
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
343
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
344 The callback is a standard libuv pattern, extracting the data from the watcher.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
345
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
346 Finally it is important to remember to clean up the watcher.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
347
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
348 .. rubric:: progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
349 .. literalinclude:: ../../code/progress/main.c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
350 :language: c
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
351 :linenos:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
352 :lines: 26-29
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
353 :emphasize-lines: 3
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
354
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
355 After this example, which showed the abuse of the ``data`` field, bnoordhuis_
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
356 pointed out that using the ``data`` field is not thread safe, and
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
357 ``uv_async_send()`` is actually only meant to wake up the event loop. Use
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
358 a mutex or rwlock to ensure accesses are performed in the right order.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
359
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
360 .. note::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
361
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
362 mutexes and rwlocks **DO NOT** work inside a signal handler, whereas
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
363 ``uv_async_send`` does.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
364
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
365 One use case where ``uv_async_send`` is required is when interoperating with
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
366 libraries that require thread affinity for their functionality. For example in
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
367 node.js, a v8 engine instance, contexts and its objects are bound to the thread
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
368 that the v8 instance was started in. Interacting with v8 data structures from
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
369 another thread can lead to undefined results. Now consider some node.js module
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
370 which binds a third party library. It may go something like this:
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
371
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
372 1. In node, the third party library is set up with a JavaScript callback to be
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
373 invoked for more information::
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
374
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
375 var lib = require('lib');
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
376 lib.on_progress(function() {
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
377 console.log("Progress");
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
378 });
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
379
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
380 lib.do();
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
381
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
382 // do other stuff
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
383
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
384 2. ``lib.do`` is supposed to be non-blocking but the third party lib is
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
385 blocking, so the binding uses ``uv_queue_work``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
386
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
387 3. The actual work being done in a separate thread wants to invoke the progress
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
388 callback, but cannot directly call into v8 to interact with JavaScript. So
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
389 it uses ``uv_async_send``.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
390
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
391 4. The async callback, invoked in the main loop thread, which is the v8 thread,
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
392 then interacts with v8 to invoke the JavaScript callback.
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
393
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
394 ----
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
395
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
396 .. _node.js is cancer: http://widgetsandshit.com/teddziuba/2011/10/node-js-is-cancer.html
948de3f54cea [ThirdParty] Added libuv
June Park <parkjune1995@gmail.com>
parents:
diff changeset
397 .. _bnoordhuis: https://github.com/bnoordhuis