libuv是node.js使用的基础库,主要包括主循环,文件和网络接口。虽然libuv是为node.js而生的,但它本身是一个独立的库,加上使用简单方便,所以在node.js之外也有不少人使用。最近整合libuv到V8里时发现几个问题:

1.uv_fs相关函数无法传回调函数需要的上下文信息(如read的buffer),只能通过全局变量来保存数据(官方例子都是用的全局变量)。uv_fs相关函数都可以提供一个回调函数,如果回调函数不为空,当前调用自动变成一个异步调用,在操作完成时调用提供的回调函数。一般来说,回调函数都需要一个变量来作为它的上下文(提供参数或保存结果),文件操作相关函数的上下文是uv_fs_t结构,但里面无法保存调用者提供的额外信息。

uv_fs_t open_req;
uv_fs_t read_req;
uv_fs_t write_req;static char buffer[1024];static uv_buf_t iov;
...
void on_read(uv_fs_t *req) {if (req->result < 0) {fprintf(stderr, "Read error: %s\n", uv_strerror(req->result));}else if (req->result == 0) {uv_fs_t close_req;// synchronousuv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL);}else if (req->result > 0) {iov.len = req->result;uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, on_write);}
}void on_open(uv_fs_t *req) {// The request passed to the callback is the same as the one the call setup// function was passed.assert(req == &open_req);if (req->result >= 0) {iov = uv_buf_init(buffer, sizeof(buffer));uv_fs_read(uv_default_loop(), &read_req, req->result,&iov, 1, -1, on_read);}else {fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result));}
}
...
uv_fs_open(uv_default_loop(), &open_req, argv[1], O_RDONLY, 0, on_open);

我开始以为data成员是保存用户数据的地方,通过data把buffer传过去,但是data总是被清空了,看里面的代码才知道data是fs内部的使用的。上面官方例子都是通过全局变量传过去的,真是太变态了!

2.其它线程不能访问缺省主循环。最近让cantk-runtime-v8里支持Touch/Key事件遇到这个问题:Touch/Key事件是UI线程里的,而V8是在GLSurfaceView的Render线程里的,直接通过JNI调用V8里的JS会导致程序崩溃,所以我想通过uv_idle来串行化,但结果是程序仍然崩溃。记得glib loop里idle是允许多线程访问的,我在设计FTK的主循环时也通过一个pipe来串行化多线程访问主循环的,呵呵,我以为所有的loop都应该支持多线程,一看代码才知道,它并没有加锁也没有用pipe来串行化:

  int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) {           \if (uv__is_active(handle)) return 0;                                      \if (cb == NULL) return -EINVAL;                                           \QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue);         \handle->name##_cb = cb;                                                   \uv__handle_start(handle);                                                 \return 0;                                                                 \}    

3.uv_async无法传递数据。用uv_idle不行,我决定用uv_async。这次倒是不崩溃了,事件好像也收到了,但游戏里的反应却有些怪异,仔细分析LOG信息,发现touchmove和touchend收到了,但是没有收到touchstart。明明uv_async_send都执行了,为什么主循环却没有处理这个事件呢?继续看代码:

void uv__async_send(struct uv__async* wa) {const void* buf;ssize_t len;int fd;int r;buf = "";len = 1;fd = wa->wfd;#if defined(__linux__)if (fd == -1) {static const uint64_t val = 1;buf = &val;len = sizeof(val);fd = wa->io_watcher.fd;  /* eventfd */}
#endifdor = write(fd, buf, len);while (r == -1 && errno == EINTR);if (r == len)return;if (r == -1)if (errno == EAGAIN || errno == EWOULDBLOCK)return;abort();
}

async_send是同步执行的,从上面的代码看不出什么问题,再看接受部分:

static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {struct uv__async* wa;char buf[1024];unsigned n;ssize_t r;n = 0;for (;;) {r = read(w->fd, buf, sizeof(buf));if (r > 0)n += r;if (r == sizeof(buf))continue;if (r != -1)break;if (errno == EAGAIN || errno == EWOULDBLOCK)break;if (errno == EINTR)continue;abort();}wa = container_of(w, struct uv__async, io_watcher);#if defined(__linux__)if (wa->wfd == -1) {uint64_t val;assert(n == sizeof(val));memcpy(&val, buf, sizeof(val));  /* Avoid alignment issues. */wa->cb(loop, wa, val);return;}
#endifwa->cb(loop, wa, n);
}

全部数据读取完了,只是在最后调了一次回调。更郁闷的是我对async的理解是错的:uv_async_t里的data成员并不能用来传递数据,它是在两个线程中无保护的情况下共享的。下面的代码是官方提供的示例,这种方法在低速通信时没问题,速度一快后面的数据自动覆盖前面的数据,所以touchstart被touchmove覆盖而丢失。

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;}
}

libuv以上这些问题在node.js恰恰不是问题,但独立使用libuv时一定要小心了。

libuv里的几个缺陷相关推荐

  1. Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)

    UIL( Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)) http://blog.csdn.net/vipzjyno1/article/detai ...

  2. libuv 高性能事件驱动库 简介

    libuv是一个高性能事件驱动库,屏蔽了各种操作系统的差异从而提供了统一的API.libuv严格使用异步.事件驱动的编程风格.其核心工作是提供事件循环及基于 I/O或其他活动事件的回调机制.libuv ...

  3. Libuv源码分析 —— 8. 线程池

    网络I/O 在 上一节 的学习中,我们已经搞明白了网络I/O的基本过程,并通过了解进程/线程间通信来熟悉这个流程.下面,让咱们学习线程池中的线程如何工作.并和主进程进行通信的吧! 线程池 Libuv ...

  4. 【缺陷管理】9:偶尔出现的缺陷如何处理?

    (1) 考虑各方面的因素来判断缺陷的严重级别和优先级别. 首先判断严重级别:严重级别比较容易判断,和其他能复现的缺陷一样处理.然后判断优先级别,就需要看对用户的影响,即需要知道这个缺陷能被复现的概率, ...

  5. 软件缺陷是什么以及缺陷的管理

    1 软件测试缺陷 软件缺陷的定义 软件缺陷,通常又被叫做Bug或者defect,即为软件或程序中存在的某种破坏正常运行能力的问题.错误.其存在会导致软件产品在某种程度上不能满足用户的需求. 软件缺陷是 ...

  6. 专访蒋宇捷:技术管理者应具备哪些能力?

    编程初体验 CSDN:你何时开始接触计算机,又如何走上编程道路的? 蒋宇捷:小学的时候,父母单位的苹果机.386和586都可以让我在空闲时候使用.而在那时代彩色显示器非常少见,即使一个小小的黑白屏幕的 ...

  7. 介绍 Java 平台的 Jazzy:一种新的拼写检查器 API

    计算机擅长执行快速搜索操作,可以根据给定的搜索词,对大量存储的信息快速进行搜索.但是,拼写检查应用程序所要求的搜索能力,不仅仅是正确的字符串匹配.在这篇文章中,我将介绍搜索算法的一些历史,包括语音匹配 ...

  8. 基于正样本的表面缺陷检测

    表面缺陷检测在工业生产中起着非常重要的作用,基于机器视觉的表面缺陷检测可以极大的提升工业生产的效率.随着近年来深度学习在计算机视觉领域的发展,卷积神经网络在诸多图像任务上都取得了显著的效果,然而这些方 ...

  9. 读《图解HTTP》总结--第九章

    基于HTTP的功能追加协议 虽然HTTP协议即简单又简捷,但随着时代的发展,其功能使用上捉襟见肘的疲态已经凸显.本篇主要讲解基于HTTP新增的功能的协议. 9.1  基于HTTP的协议 在建立HTTP ...

最新文章

  1. Redis运行流程源码解析
  2. SpringSecurity过滤器链汇总
  3. 刚才我提出要把数据库处理部分放到代码里,但是有人提出,存储过程有缓存,速度快。我该怎么说啊?...
  4. 【计算理论】计算复杂性 ( 两个带子的图灵机的时间复杂度 | 证明多个带子图灵机时间复杂度 )
  5. Win7下Android模拟器中没有3G网络信号的解决办法
  6. 【英语学习】【Daily English】U10 Education L01 Is this certificate a must?
  7. 快手与美团达成互联互通合作:美团将在快手上线小程序
  8. Eclipse探秘-第一章-Eclipse启动(1)
  9. 中国地图经纬度json
  10. 西门子200PLC控制台达伺服电机正反转,步科触摸屏,模拟量控制
  11. 一杯咖啡带你读懂状态机
  12. 前端tif文件在线预览
  13. 芯片级维修学习课程安排
  14. C++数组能开多大?
  15. 视觉欺骗:你绝不会相信A和B颜色相同!
  16. 华夏ERP没有找到新增功能
  17. JS 实现驼峰式转下横线,下横线转驼峰式2
  18. 多线程的实现与多线程的同步机制-让你轻松掌握多线程编程
  19. Qt编写可视化大屏电子看板系统5-恢复布局
  20. 如何整理企业的知识库?

热门文章

  1. scrollIntoView()实现简单的锚点定位
  2. 网络营销专家分析SNS社区一般推广方式及要点
  3. Cesium-通过Shader添加雨雪天气效果
  4. 计算机配色故障,计算机配色不理想?究竟问题出在哪?数据库,很重要!
  5. 【C2M】C2M模式为中国制造提出了创新发展思路
  6. 580解锁bl工具_爱折腾的用户有福利了:Realme官方可解锁BL,刷机工具走起
  7. 超轻量级的Gow,替代cgwin
  8. 智能家居Homekit系列一智能触摸开关
  9. 易语言 标准c 动态库,易语言Dll动态库的开发
  10. Bahdanau 注意力