最近有一个需求,要求写一个Redis客户端,要求跨平台,找了些资料研究了一下,决定用libuv,于是开干。
思路:
基于业务考虑,将uv_loop放在线程中运行中,发送使用uv_async_init实现跨线程。
注意事项:
1. uv_loop_t、uv_work_t、uv_async_t等变量最好在线程中分配资源,uv_default_loop方法务必在线程中调用,uv_run在线程结尾调用,使用线程阻塞。uv_async_t最好提前分配好(之前没用event、wait的时候每次uv_async_send时new uv_async_t对象会出现崩溃,疑似线程安全问题)。
2. uv_async_send是线程安全的非阻塞函数,可将参数通过uv_async_t->data传递到回调函数中,但存在一个问题,uv_async_send速度如果大于回调函数处理速度,有些函数无法执行。因此建议建议使用event,wait机制实现同步(仅表示线程通信同步)。
3. 虽然支持多线程,但工作线程数量上限是4个(环境:windows 10,CPU:AMD 6核12线程)。
4. 没有直观disconnect回调,实现起来要靠uv_read间接实现,不直观。(这也是作者改用libevent的主要原因)。
分析:
未解读libuv源码,猜测原因为全局事件队列导致。至于线程数上限问题,还需要进一步解读源码,此处只是记录一下应用时遇到的坑,避免下次再跳进去。
附代码(Windows平台测试代码):
#include <string>
#include <functional>
#include <mutex>
#include <map>
#include <iostream>
#include "../libuv/include/uv.h"
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "IPHLPAPI.lib") // GetAdaptersAddresses
//#pragma comment(lib, "Kernel32.lib") // GetProcessMemoryInfo
#pragma comment(lib, "Psapi.lib") // GetProcessMemoryInfo
#pragma comment(lib, "Userenv.lib") // GetUserProfileDirectory
#pragma comment(lib, "Secur32.lib