程序发布后在一个用户的机器上频繁出现崩溃,最终定位到崩溃来自一个断言失败:
assert(pthread_self() != main_thread_id);
上面这条语句出现在工作线程回调的函数中,竟然发生了工作线程ID和主线程ID相同的怪事,观察了运行日志,发现使用libcurl发起HTTP请求如果超时则有很大机率会断言失败导致崩溃,在使用libcurl发起HTTP请求的代码块前后输出工作线程ID,工作线程ID出现了变化,根据经验很可能是出现了内存越界。
最终找到了几篇 libcurl
多线程安全相关的文章:
修复步骤总结如下:
在主线程起始处初始化
libcurl
库curl_global_init(CURL_GLOBAL_ALL);
禁止
libcurl
通过alarm
实现域名解析超时curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
如果不做下面的最后一步,
libcurl
上设置的超时都会无效。编译
libcurl
时启用c-ares
或threaded resolver
,以支持域名解析超时./configure --enable-ares
或
./configure --enable-threaded-resolver
《Asynch resolving in libcurl》对
c-ares
或threaded resolver
两种方式进行了比较,简而言之:c-ares
是一个异步的域名解析库,开销更少,但是它并非使用系统原生的方式实现,对于定制系统(如:hosts或resolv.conf不在标准位置)可能会有问题。threaded resolver
每次域名解析都会开一个线程,解析完成后销毁线程,开销会大一些,但是稳定性、兼容性更好。
按照上面的步骤启用 c-ares
进行修改后程序运行了一整天,没有再崩溃。