XS-libuv
view release on metacpan or search on metacpan
libuv-1.49.2/docs/src/guide/threads.rst view on Meta::CPAN
It is important to realize that since the message send is *async*, the callback
may be invoked immediately after ``uv_async_send`` is called in another
thread, or it may be invoked after some time. libuv may also combine
multiple calls to ``uv_async_send`` and invoke your callback only once. The
only guarantee that libuv makes is -- The callback function is called *at
least once* after the call to ``uv_async_send``. If you have no pending
calls to ``uv_async_send``, the callback won't be called. If you make two
or more calls, and libuv hasn't had a chance to run the callback yet, it
*may* invoke your callback *only once* for the multiple invocations of
``uv_async_send``. Your callback will never be called twice for just one
event.
.. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c
:language: c
:linenos:
:lines: 10-24
:emphasize-lines: 7-8
In the download function, we modify the progress indicator and queue the message
for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also
non-blocking and will return immediately.
.. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c
:language: c
:linenos:
:lines: 31-34
The callback is a standard libuv pattern, extracting the data from the watcher.
Finally it is important to remember to clean up the watcher.
.. rubric:: progress/main.c
.. literalinclude:: ../../code/progress/main.c
:language: c
:linenos:
:lines: 26-29
:emphasize-lines: 3
After this example, which showed the abuse of the ``data`` field, bnoordhuis_
pointed out that using the ``data`` field is not thread safe, and
``uv_async_send()`` is actually only meant to wake up the event loop. Use
a mutex or rwlock to ensure accesses are performed in the right order.
.. note::
mutexes and rwlocks **DO NOT** work inside a signal handler, whereas
``uv_async_send`` does.
One use case where ``uv_async_send`` is required is when interoperating with
libraries that require thread affinity for their functionality. For example in
node.js, a v8 engine instance, contexts and its objects are bound to the thread
that the v8 instance was started in. Interacting with v8 data structures from
another thread can lead to undefined results. Now consider some node.js module
which binds a third party library. It may go something like this:
1. In node, the third party library is set up with a JavaScript callback to be
invoked for more information::
var lib = require('lib');
lib.on_progress(function() {
console.log("Progress");
});
lib.do();
// do other stuff
2. ``lib.do`` is supposed to be non-blocking but the third party lib is
blocking, so the binding uses ``uv_queue_work``.
3. The actual work being done in a separate thread wants to invoke the progress
callback, but cannot directly call into v8 to interact with JavaScript. So
it uses ``uv_async_send``.
4. The async callback, invoked in the main loop thread, which is the v8 thread,
then interacts with v8 to invoke the JavaScript callback.
----
.. _node.js is cancer: http://widgetsandshit.com/teddziuba/2011/10/node-js-is-cancer.html
.. _bnoordhuis: https://github.com/bnoordhuis
( run in 1.562 second using v1.01-cache-2.11-cpan-39bf76dae61 )