官网上给出的例子http://nikhilm.github.io/uvbook/threads.html#inter-thread-communication,中文理解在后边

Inter-thread communication

Sometimes you want various threads to actually send each other messages while they are running. For example you might be running some long duration task in a separate thread (perhaps using uv_queue_work) but want to notify progress to the main thread. This is 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
9
10
11
12
13
14
15
uv_loop_t *loop;
uv_async_t async; int main() {
loop = uv_default_loop(); uv_work_t req;
int size = 10240;
req.data = (void*) &size; uv_async_init(loop, &async, print_progress);
uv_queue_work(loop, &req, fake_download, after); return uv_run(loop, UV_RUN_DEFAULT);
}

The async thread communication works on loops so although any thread can be the message sender, only threads with libuv loops can be receivers (or rather the loop is the receiver). libuv will invoke the callback (print_progress) with the async watcher whenever it receives a message.

Warning

It is important to realize that 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.

progress/main.c

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
void fake_download(uv_work_t *req) {
int size = *((int*) req->data);
int downloaded = 0;
double percentage;
while (downloaded < size) {
percentage = downloaded*100.0/size;
async.data = (void*) &percentage;
uv_async_send(&async); sleep(1);
downloaded += (200+random())%1000; // can only download max 1000bytes/sec,
// but at least a 200;
}
}

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.

progress/main.c

1
2
3
4
void print_progress(uv_async_t *handle, int status /*UNUSED*/) {
double percentage = *((double*) 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 clean up the watcher.

progress/main.c

1
2
3
4
void after(uv_work_t *req, int status) {
fprintf(stderr, "Download complete\n");
uv_close((uv_handle_t*) &async, NULL);
}

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.

这个也有中文版的翻译,可以网上搜到。

文中最后提到的uv_async_t.data不是线程安全的,我的理解如下:

在主线程中开启一个消息循环loop(uv_loop_t对象),然后为loop注册了一个异步消息监听器async(uv_async_t对象),其他线程就可以通过async给主线程发送消息。做法就是把数据保存在async下,然后将async发给loop,loop异步的获取async,然后从async中得到数据并处理。我想说的是,async对象只有一个,在传递的过程中没有副本,因此从发送消息到消息被获取并处理完毕,这期间async对象都是线程不安全的,应该加上同步机制来保证整个期间async对象只服务于一个其他线程。但是如果同步的话,那libuv提供的异步消息机制岂不没有用了?我们的多线程程序也会在此遇到瓶颈。

我的解决方法有两个:

1.其他线程在每次向主线程发送消息的时候,都新建一个async对象,并临时注册到loop里;当loop获取该async对象,处理完毕后,注销并并删除async对象

2.同时注册多个async对象,将他们保存在队列中。其他线程在向主线程发送消息时,互斥的获取其中一个async对象,等loop处理完该async对象后,将其互斥的插回队列。虽然这样也有同步操作,但它的同步周期大大减小,提高了线程并行度。

libuv的多线程之间传递消息的更多相关文章

  1. EventBus的使用详解,功能为在Fragment,Activity,Service,线程之间传递消息

    最近跟同事用到了EventBus的使用,之前不太了解EventBus,查阅资料发现EventBus还挺好用的,用法比较简单,下面就把我看到的关于EventBus的博客分享给大家,里面介绍了很多的使用详 ...

  2. 用WM_COPYDATA消息来实现两个进程之间传递数据

    文着重讲述了如果用WM_COPYDATA消息来实现两个进程之间传递数据. 进程之间通讯的几种方法:在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.常用的方法有   1.使用内存映射 ...

  3. 安卓中不同APP之间的消息通信

    昨天在腾讯实习生招聘初试面试时面试官问道我关于两个APP之间相互通信的方式,当时自己回道到了contentProvider与BroadcastReceiver.但他接着问还有没有其它的方式,我跟他说可 ...

  4. Android消息传递之组件间传递消息

    前言: 上篇学习总结了Android通过Handler消息机制实现了工作线程与UI线程之间的通信,今天来学习一下如何实现组件之间的通信.本文依然是为学习EventBus做铺垫,有对比才能进步,今天主要 ...

  5. Android开发--Service和Activity通过广播传递消息

    Android的Service也运行在主线程,但是在服务里面是没法直接调用更改UI,如果需要服务传递消息给Activity,通过广播是其中的一种方法: 一.在服务里面发送广播 通过intent传送数据 ...

  6. javascript跨域传递消息 / 服务器实时推送总结

    参考文档,下面有转载[非常好的两篇文章]: http://www.cnblogs.com/loveis715/p/4592246.html [跨源的各种方法总结] http://kb.cnblogs. ...

  7. 【Cocos2dx游戏开发】CCNotificationCenter传递消息和数据

    在开发游戏的时候我们经常需要在层与层之间.场景与场景之间传递数据和消息,Cocos2dx框架应用观察者模式为我们封装了一个CCNotificationCenter类,也叫消息通知中心,它也是一个单例类 ...

  8. H5 页面与小程序之间 传递数据

    H5 页面与小程序之间 传递数据 小程序里面的 H5页面与小程序之间怎么传递数据 webview与小程序之间的实时通信 webview主动发消息给小程序 webview可以利用jssdk提供的 wx. ...

  9. 大叔也说Xamarin~Android篇~Activity之间传递数组

    回到目录 我们在开发应用程序时,不可能只使用一个Layout或者一个Activity,比如你个管理系统,要求用户先登陆然后再使用,这时你至少要有两个activity吧,先登陆一个,然后成功后需要跳到别 ...

随机推荐

  1. ES6的新特性(11)——Class 的继承

    Class 的继承 简介 Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多. class Point { } class ColorPoint ...

  2. Bate版本控制报告

    报告beta阶段2周中,项目的版本控制情况,不包括未在coding.net的部分. 包括不限于:check in (不是push)次数; 总词数为29次 check in log(时间.人员.mess ...

  3. spring表单—乱码解决方案

    1.POST方式提交 A.jsp页面POST方式提交表单 B.web.xml配置过滤器 <!-- spring过滤器解决乱码问题 --> <filter> <filter ...

  4. selenium 概念及练习 !

    1.selenium中如何判断元素是否存在? 2.selenium中hidden或者是display = none的元素是否可以定位到? 3.selenium中如何保证操作元素的成功率?也就是说如何保 ...

  5. GO语言教程(一)Linux( Centos)下Go的安装, 以及HelloWorld

    写在前面: 目前,Go语言已经发布了1.5的版本,已经有不少Go语言相关的书籍和教程了,但是看了一些后,觉得还是应该自己写一套Go语言的教程.给广大学习Go语言的朋友多一种选择.因为,咱写的教程,向来 ...

  6. php伪静态配置

    配置虚拟主机和伪静态 1.开启Apache的rewrite模块 LoadModule rewrite_module modules/mod_rewrite.so 2.开启虚拟主机功能 # Virtua ...

  7. pyspark在windows中的安装

    0.安装python,我用的是python2.7.13 1.安装jdk 一定要安装1.7以上的版本,安装低版本会报下面的错误 java.lang.NoclassDefFoundError 安装后不用手 ...

  8. 第196天:js---调用函数的五种方式

    一.普通方式 /*普通模式*/ // 声明一个函数,并调用 function func() { console.log("Hello World"); } func(); 二.函数 ...

  9. 【bzoj3796】Mushroom追妹纸 Kmp+二分+Hash

    题目描述 给出字符串s1.s2.s3,找出一个字符串w,满足: 1.w是s1的子串: 2.w是s2的子串: 3.s3不是w的子串. 4.w的长度应尽可能大 求w的最大长度. 输入 输入有三行,第一行为 ...

  10. equals与==区别

    equals与==区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolean   他们之间 ...