Official web-based example Http://nikhilm.github.io/uvbook/threads.html#inter-thread-communication, Chinese understanding behind
Inter-thread Communication
Sometimes want various threads to actually send each other messages while they is running. For example might is running some long duration task in a separate thread (perhaps using uv_queue_work) but W Ant to notify progress to the main thread. This was a simple example of having a download manager informing the user of the status of running downloads.
Progress/main.c
1 2 3 4 5 6 7 8 9101112131415 |
uv_loop_t*Loop;uv_async_tAsync;IntMain(){Loop=Uv_default_loop();uv_work_tReq;IntSize=10240;Req.Data= (void*) & Size; uv_async_init (loop& asyncprint_progress); uv_queue_work (loop& reqfake_downloadafter ); return uv_run (loop uv_run_default); /span> |
The async thread communication works on loops so although no thread can be the message sender, only threads with LIBUV loops can be receivers (or rather the loop is the receiver). LIBUV would invoke the callback (print_progress) with the Async watcher whenever it receives a message.
Warning
It is important to realize this message send isAsync, the callback May is invoked immediately afterUv_async_sendWas called in another thread, or it could be invoked after some time. LIBUV also combine multiple calls toUv_async_sendand invoke your callback only once. The only guarantee, LIBUV makes Is–the callback function is calledAt least onceAfter the call toUv_async_send. If you have no pending calls toUv_async_sendThe callback won ' t be called. If you make both or more calls, and libuv hasn ' t had a chance to run the callback yet, it MayInvoke your callbackOnly onceFor the multiple invocations ofUv_async_send. Your callback'll never is called twice for just one event.
Progress/main.c
1 2 3 4 5 6 7 8 91011121314 |
voidFake_download(uv_work_t*Req){IntSize=*((Int*)Req-Data);IntDownloaded=0;DoublePercentage;While(Downloaded<Size){Percentage=Downloaded*100.0/Size; async. Data = (void*) &percentage; uv_async_send (&asyncsleep (1downloaded += (200+ random ()) %1000//can only download Max 1000bytes/sec, //but at least a 200; }} /span> |
In the download function we modify the progress indicator and queues the message for delivery with Uv_async_send. Remember: uv_async_send is also non-blocking and would return immediately.
Progress/main.c
1234 |
void print_progress (uv_async_t *handleint status /*unused*/) {double percentage = * ((double*) span class= "n" >handle->data); fprintf (stderr "downloaded%.2f %%\n "percentage); }
|
The callback is a standard LIBUV pattern, extracting the data from the watcher.
Finally It is important to remember to the watcher.
Progress/main.c
1234 |
void after (uv_work_t * reqint status) {fprintf (stderr "Download complete\n" ); uv_close ((uv_handle_t*) &asyncnull); } |
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 () are actually only meant to wake up the event loop. Use a mutex or rwlock to ensure accesses is performed in the right order.
This also has the Chinese version of the translation, can be searched online.
The last mentioned uv_async_t.data is not thread-safe, and I understand the following:
A message loop loop (Uv_loop_t object) is opened in the main thread, and an asynchronous Message listener async (uv_async_t object) is registered for the loop, and other threads can send messages to the main thread via async. The practice is to save the data under Async, then send async to Loop,loop asynchronously to get async, and then get the data from async and handle it. I want to say that there is only one async object, there is no copy in the process of delivery, so from the sending message to the message is fetched and processed, during which the Async object is thread insecure, and should be coupled with a synchronization mechanism to ensure that the entire period of the Async object to serve only one other thread. But what if the asynchronous messaging mechanism provided by LIBUV is not used when synchronizing? Our multi-threaded threads will also encounter bottlenecks here.
There are two ways to solve my problem:
1. Each time the other thread sends a message to the main thread, it creates a new async object and temporarily registers it with the loop; when the loop gets the async object, it finishes, logs off and deletes the async object
2. Register multiple Async objects at the same time and save them in the queue. When other threads send a message to the main thread, the mutex obtains one of the async objects, and when the loop finishes processing the Async object, it is mutually exclusive and inserted back into the queue. Although this also has synchronous operation, its synchronization period is greatly reduced, and the degree of thread parallelism is improved.
Passing messages between multiple threads of LIBUV