2010-07-19 111 views
7

所以我有一堆工作线程做简单的卷曲类,每个工作线程都有自己的卷曲简单句柄。他们只对随机网站进行HEAD查找。还有锁定功能可用于启用多线程SSL,如文档here所述。一切工作除了在2个网页ilsole24ore.com(例如,在看到下),并ninemsn.com.au/,他们有时会产生赛格如图跟踪输出这里libcurl中的分段错误,多线程

#0 *__GI___libc_res_nquery (statp=0xb4d12df4, name=0x849e9bd "ilsole24ore.com", class=1, type=1, answer=0xb4d0ca10 "", anslen=1024, answerp=0xb4d0d234, 
     answerp2=0x0, nanswerp2=0x0, resplen2=0x0) at res_query.c:182 
    #1 0x00434e8b in __libc_res_nquerydomain (statp=0xb4d12df4, name=0xb4d0ca10 "", domain=0x0, class=1, type=1, answer=0xb4d0ca10 "", anslen=1024, 
     answerp=0xb4d0d234, answerp2=0x0, nanswerp2=0x0, resplen2=0x0) at res_query.c:576 
    #2 0x004352b5 in *__GI___libc_res_nsearch (statp=0xb4d12df4, name=0x849e9bd "ilsole24ore.com", class=1, type=1, answer=0xb4d0ca10 "", anslen=1024, 
     answerp=0xb4d0d234, answerp2=0x0, nanswerp2=0x0, resplen2=0x0) at res_query.c:377 
    #3 0x009c0bd6 in *__GI__nss_dns_gethostbyname3_r (name=0x849e9bd "ilsole24ore.com", af=2, result=0xb4d0d5fc, buffer=0xb4d0d300 "\177", buflen=512, 
     errnop=0xb4d12b30, h_errnop=0xb4d0d614, ttlp=0x0, canonp=0x0) at nss_dns/dns-host.c:197 
    #4 0x009c0f2b in _nss_dns_gethostbyname2_r (name=0x849e9bd "ilsole24ore.com", af=2, result=0xb4d0d5fc, buffer=0xb4d0d300 "\177", buflen=512, 
     errnop=0xb4d12b30, h_errnop=0xb4d0d614) at nss_dns/dns-host.c:251 
    #5 0x0079eacd in __gethostbyname2_r (name=0x849e9bd "ilsole24ore.com", af=2, resbuf=0xb4d0d5fc, buffer=0xb4d0d300 "\177", buflen=512, result=0xb4d0d618, 
     h_errnop=0xb4d0d614) at ../nss/getXXbyYY_r.c:253 
    #6 0x00760010 in gaih_inet (name=<value optimized out>, service=<value optimized out>, req=0xb4d0f83c, pai=0xb4d0d764, naddrs=0xb4d0d754) 
     at ../sysdeps/posix/getaddrinfo.c:531 
    #7 0x00761a65 in *__GI_getaddrinfo (name=0x849e9bd "ilsole24ore.com", service=0x0, hints=0xb4d0f83c, pai=0xb4d0f860) at ../sysdeps/posix/getaddrinfo.c:2160 
    #8 0x00917f9a in ??() from /usr/lib/libkrb5support.so.0 
    #9 0x003b2f45 in krb5_sname_to_principal() from /usr/lib/libkrb5.so.3 
    #10 0x0028a278 in ??() from /usr/lib/libgssapi_krb5.so.2 
    #11 0x0027eff2 in ??() from /usr/lib/libgssapi_krb5.so.2 
    #12 0x0027fb00 in gss_init_sec_context() from /usr/lib/libgssapi_krb5.so.2 
    #13 0x00d8770e in ??() from /usr/lib/libcurl.so.4 
    #14 0x00d62c27 in ??() from /usr/lib/libcurl.so.4 
    #15 0x00d7e25b in ??() from /usr/lib/libcurl.so.4 
    #16 0x00d7e597 in ??() from /usr/lib/libcurl.so.4 
    #17 0x00d7f133 in curl_easy_perform() from /usr/lib/libcurl.so.4 

出故障My功能看起来像这

int do_http_check(taskinfo *info,standardResult *data) 
{ 
    standardResultInit(data); 

    char errorBuffer[CURL_ERROR_SIZE]; 

    CURL *curl; 
    CURLcode result; 

    curl = curl_easy_init(); 

    if(curl) 
    { 
     //required options first 
     curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer); 
     curl_easy_setopt(curl, CURLOPT_URL, info->address.c_str()); 
     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer); 
     curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data->body); 
     curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, writer); 
     curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &data->head); 
     curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE,0); 
     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30); 
     curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1); 
     curl_easy_setopt(curl, CURLOPT_NOBODY,1); 
     curl_easy_setopt(curl, CURLOPT_TIMEOUT ,240); 

     //optional options 
     if(info->options.follow) 
     { 
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); 
      curl_easy_setopt(curl, CURLOPT_MAXREDIRS, info->options.redirects); 
     } 

     result = curl_easy_perform(curl); 

     if (result == CURLE_OK) 
     { 
      data->success = true; 
      curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&data->httpMsg); 
      curl_easy_getinfo(curl,CURLINFO_REDIRECT_COUNT,&data->numRedirects); 
      data->msg = "OK"; 
     } 
     else 
     { 
      ... handle error 
     } 


    return 1; 
} 

现在,当我打电话功能,无需任何线程,只需调用它从主就从来没有断,所以我想它的连接线,或被也许是如何返回数据结构中返回,但是从我在跟踪中看到它看起来像是在easy_perform()调用中生成的故障,它令我困惑。 所以,如果有人有任何想法,我应该看看下一个这将是最有帮助的,谢谢。

回答

13

libcurl to Multi-Threading有专门的整节。

第一个基本规则是,你必须 从来没有共享libcurl的句柄(无论是 容易或多或其他) 之间的多个线程。一次只能在一个线程中使用一个手柄 。

libcurl完全线程安全, 除了两个问题:信号和 SSL/TLS处理程序。信号用于 超时名称解析(在DNS 查找期间) - 当没有c-ares 支持而不是在Windows上时。

如果您正在访问HTTPS或FTPS 的URL在一个多线程的方式,你 然后当然使用 基础SSL库多线程 和那些库可能对这个问题自己 要求。基本上, 您需要提供一个或两个 函数以使其正确运行 。对于所有的详细信息,请参阅本:

OpenSSL的

http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION

的GnuTLS

http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html

NSS

自称是线程安全已经 而不需要任何东西。

yassl

需要操作未知。

当使用多个线程时,您应该为所有句柄设置CURLOPT_NOSIGNAL选项为1 。一切将或 可能会正常工作,但超时 在DNS查找 期间没有兑现 - 你可以通过构建带有c-ares支持的libcurl来解决。 c-ares是一个提供 异步名称解析的库。在某些 平台上,除非设置了此选项,否则libcurl根本不会 正常运行多线程 。

另外,请注意, CURLOPT_DNS_USE_GLOBAL_CACHE不是 线程安全。

+0

是的,我读过卷曲的一部分,我的计划遵循所有的指导方针。但是我找到了这个问题,它没有卷毛,只是调试器指向那里。我确实学到了一些关于卷曲的新东西,无论如何。 – Mogwai 2010-07-20 11:28:44

0

error: longjmp causes uninitialized stack frame提到的,在于Debian/Ubuntu储存库中的最新版本的libcurl(> = 7.32.0)包含一个新的多线程分解器来解决这些问题。在C-战神的支持是不是一个很好的解决方案:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570436#74

“真正的问题是,C-战神尚未对gethostby *函数(例如,它不支持组播DNS)和启用全部更换它有股票libcurl包可能不是一个好的举措(请注意,这些都是卷曲和c - ares的上游作者的话,而不是我的)。“ -