官网上给出的例子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. 20135313_exp4

    实验四      GUI界面的设计和运用 20135313吴子怡 一.实验目的 结合项目,为每个密码学算法设计能够提供使用者用户体验的操作界面,实现加解密.求得消息摘要的功能. 二.代码举例(备注:其 ...

  2. tensorflow之分类学习

    写在前面的话 MNIST教程是tensorflow中文社区的第一课,例程即训练一个 手写数字识别 模型:http://www.tensorfly.cn/tfdoc/tutorials/mnist_be ...

  3. 3dContactPointAnnotationTool开发日志(三四)

      今天就是让背景图可以变大变小,变透明度,然后将3d的点投影到图片上,输出2d接触点信息:   可以看到输出了正确的接触点信息:   然后还把空物体的包围盒大小设置为边长为0.1的的正方体,点击选中 ...

  4. QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开     本文地址:h ...

  5. 第二周:PSP&进度条

    PSP: 一.词频统计改进 1.表格:     C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(hrs) 学习 <构建之法>.Java 8:46 1 ...

  6. CodeForces Round #527 (Div3) B. Teams Forming

    http://codeforces.com/contest/1092/problem/B There are nn students in a university. The number of st ...

  7. (十)Jmeter中的Debug Sampler介绍

    一.Debug Sampler介绍: 使用Jmeter开发脚本时,难免需要调试,这时可以使用Jmeter的Debug Sampler,它有三个选项:JMeter properties,JMeter v ...

  8. JS扫雷原理性代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. mysql中一些表选项

    表选项列表 表选项就是,创建一个表的时候,对该表的整体设定,主要有如下几个: charset = 要使用的字符编码, engine = 要使用的存储引擎(也叫表类型), auto_increment ...

  10. Mybatis 映射关系

    相比 Hibernate,Mybatis 的映射关系就显得简单了很多. 未完待续....