

新闻资讯
技术学院libcurl多线程与libevent驱动不可混用:前者为阻塞I/O+pthread,后者为单线程非阻塞事件循环;必须通过curl_multi_*接口配合socket事件通知,动态管理libevent的event实例,并严格同步socket生命周期与HTTP/2/TLS事件。
直接用 pthread 创建多个线程跑 curl_easy_perform(),和用 libevent 驱动 libcurl 的异步接口(curl_multi_*)是两套完全不同的模型。前者是阻塞 I/O + 线程并发,后者是单线程事件循环 + 非阻塞 I/O。强行在线程里嵌套 libevent 主循环或在 libevent 回调里调 curl_easy_perform(),大概率触发死锁或未定义行为。
libcurl 的异步能力只通过 curl_multi_* 系列函数暴露,必须配合其内部的 socket 事件通知机制libevent 不能直接“接管” curl_easy_handle,只能监听 curl_multi_socket_action() 返回的 socket fd 变化CURLM 句柄需绑定一个独立的 libevent struct event_base *,不可跨 base 共享核心在于把 libcurl 多接口句柄的 socket 状态变化,转为 libevent 可监听的事件。关键步骤不是“注册回调”,而是动态管理 event 实例:
curl_multi_socket_action(multi_handle, CURL_SOCKET_TIMEOUT, 0, &still_running) 获取超时值,用 event_add(
) 设置定时器curl_multi_socket_action() 返回新 socket fd 或状态变更,用 event_del() 清旧 event,再用 event_new() + event_add() 注册新监听(EV_READ/EV_WRITE)curl_multi_socket_action(),否则 curl 内部状态不同步
static void curl_perform_cb(int fd, short kind, void *userp) {
CURLM *multi = (CURLM *)userp;
int action = (kind & EV_READ) ? CURL_CSELECT_IN : CURL_CSELECT_OUT;
int running_handles;
curl_multi_socket_action(multi, fd, action, &running_handles);
}
libcurl 可能在任意时刻通过 CURLMOPT_SOCKETFUNCTION 回调告诉你:“这个 fd 我不用了,请删掉对应 event”。但如果你在 libevent 回调里刚调完 curl_multi_socket_action() 就立刻 event_free(),而 libcurl 内部还在引用该 fd,就会 crash。
curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb)
sock_cb 中收到 action == CURL_POLL_REMOVE 时,仅标记待清理,**不立即 free event**;等下一次 curl_multi_socket_action() 调用前统一清理event 必须用 event_set() 初始化而非 event_new(),避免重复分配内存导致悬挂指针启用 CURLOPT_HTTP_VERSION = CURL_HTTP_VERSION_2TLS 后,libcurl 可能触发额外的非 socket 事件(如 ALPN 协商、HPACK 解码),这些不会反映在 socket fd 上,但会卡住 curl_multi_perform() 进度。
curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timer_cb),并在 timer_cb 中用 event_add() 更新超时,否则 HTTP/2 流控会失效SSL_read()/SSL_write() 在非阻塞模式下返回 SSL_WANT_READ/SSL_WANT_WRITE 时,libcurl 会自动重试,但要求你确保对应 socket 仍在 libevent 监听中 —— 别在 SSL_WANT_WRITE 时误删 EV_READ 事件curl_multi_setopt(multi, CURLMOPT_VERBOSITY, CURLPIPE_MULTIPLEX) 查看是否真走 HTTP/2 多路复用curl_multi_socket_action() 维系,少一次就可能卡死。