curl多線程crash分析

問題描述

在需要并發(fā)請求http時,需要通過多線程使用curl庫。curl的handle對象只要保證在一個線程中創(chuàng)建使用和銷毀,一般就不會有問題。
但是有一種類型的對象叫做curl_share,通過curl_share_init函數(shù)創(chuàng)建。用于給多個curl handle對象提供共享數(shù)據(jù),如為了降低請求延時,減少dns查詢時間,可以共享同一份dns緩存。
crash堆棧


#0  0x00007fe4339c9387 in raise () from /lib64/libc.so.6
#1  0x00007fe4339caa78 in abort () from /lib64/libc.so.6
#2  0x00007fe433a0bed7 in __libc_message () from /lib64/libc.so.6
#3  0x00007fe433a14299 in _int_free () from /lib64/libc.so.6
#4  0x00007fe434c82b6d in hash_element_dtor () from /lib64/libcurl.so.4
#5  0x00007fe434c8297f in Curl_llist_remove () from /lib64/libcurl.so.4
#6  0x00007fe434c8308a in Curl_hash_clean_with_criterium () from /lib64/libcurl.so.4
#7  0x00007fe434c5ebb7 in Curl_fetch_addr () from /lib64/libcurl.so.4
#8  0x00007fe434c5ed24 in Curl_resolv () from /lib64/libcurl.so.4
#9  0x00007fe434c763c5 in Curl_connect () from /lib64/libcurl.so.4
#10 0x00007fe434c857c3 in multi_runsingle () from /lib64/libcurl.so.4
#11 0x00007fe434c860f9 in curl_multi_perform () from /lib64/libcurl.so.4
#12 0x00007fe434c7e7db in curl_easy_perform () from /lib64/libcurl.so.4

解決方法:
設(shè)置加解鎖函數(shù)才可以加鎖保護

static void curl_dns_lock(CURL *h, curl_lock_data data, curl_lock_access access, void*userptr) {
    dns_mutex.lock();
}

static void curl_dns_unlock(CURL *h, curl_lock_data data, curl_lock_access access, void*userptr) {
    dns_mutex.unlock();
}
curl_share_setopt(dns_share_handle, CURLSHOPT_LOCKFUNC, curl_dns_lock);
curl_share_setopt(dns_share_handle, CURLSHOPT_UNLOCKFUNC, curl_dns_unlock);

分析過程分享

通過堆棧發(fā)現(xiàn)和dns有關(guān),因為有函數(shù)Curl_resolv。
查看curl源碼

git clone https://github.com/curl/curl.git
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
const char *hostname,
int port)
{
    struct Curl_dns_entry *dns = NULL;

    if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

    dns = fetch_addr(data, hostname, port);

    if(dns)
        dns->inuse++; /* we use it! */

    if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

    return dns;
}

發(fā)現(xiàn)此處獲取地址,需要加鎖。但是如果加鎖了應(yīng)該不會出crash才對。
//初始化時,是這么寫的

dns_share_handle = curl_share_init();  
curl_share_setopt(curl_dns_share_handle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);

查看share->lockfunc賦值代碼,發(fā)現(xiàn)是在curl_share_setopt中設(shè)置的:

curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) {
case CURLSHOPT_LOCKFUNC:
    lockfunc = va_arg(param, curl_lock_function);
    share->lockfunc = lockfunc;
    break;

  case CURLSHOPT_UNLOCKFUNC:
    unlockfunc = va_arg(param, curl_unlock_function);
    share->unlockfunc = unlockfunc;
    break;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容