2010-07-19 20 views
7

So habe ich eine Reihe von Worker-Threads tun, einfache Curl-Klasse, jeder Worker-Thread hat seine eigene Curl easy Handle. Sie tun nur HEAD Lookups auf zufälligen Websites. Es sind auch Sperrfunktionen vorhanden, um SSL mit mehreren Threads zu aktivieren, wie in der Dokumentation here dokumentiert. Alles funktioniert, außer auf 2 Webseiten ilsole24ore.com (in Beispiel gesehen nach unten), und ninemsn.com.au/, sie manchmal produziert seg Fehler wie in Trace-Ausgabe abgebildetSegmentierungsfehler in libcurl, Multithread

#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 

Meine Funktion sieht etwas gezeigt, wie diese

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; 
} 

, Jetzt, wenn ich rufe Funktion ohne Gewinde, ruft es nur aus dem Haupt es nie bricht, so dass ich dachte, seine zu Fäden verbunden, oder vielleicht, wie die Daten zurückgeben Struktur zurückgegeben wird, aber von dem, was ich sah in der Spur sieht es aus wie Fehler in easy_perform() Anruf generiert wird, und es verwirrende mich. Also, wenn jemand eine Idee hat, wo ich als nächstes aussehen sollte, wäre es sehr hilfreich, danke.

Antwort

13

Es gibt einen ganzen Abschnitt gewidmet in libcurl to Multi-Threading.

Die erste Grundregel ist, dass Sie müssen nie einen Libcurl Griff (seien es einfach oder mehr oder was auch immer) zwischen mehr Threads teilen. Verwenden Sie nur einen Griff in einem Thread auf einmal.

libcurl ist vollständig Thread sicher, mit Ausnahme von zwei Problemen: Signale und SSL/TLS-Handler. Signale werden für Timing-Name verwendet wird aufgelöst (während DNS Lookup) - wenn ohne c-ares Unterstützung erstellt und nicht auf Windows.

Wenn Sie HTTPS oder FTPS URLs in einer Multi-Threaded Weise zugreifen, Sie werden dann natürlich mit der zugrundeliegenden SSL-Bibliothek Multithread und diese Libs könnten ihre eigenen Anforderungen zu diesem Thema haben. Im Grunde müssen Sie eine oder zwei Funktionen zur Verfügung stellen, um es zu ermöglichen, richtig zu funktionieren. Für alle Details sehen:

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

beansprucht erforderlich Thread-sicher schon , ohne etwas zu sein.

yassl

Erforderliche Aktionen unbekannt.

Bei Verwendung mehrerer Threads sollten Sie die Option CURLOPT_NOSIGNAL auf auf 1 für alle Handles setzen.Alles wird oder könnte gut funktionieren, außer dass Timeouts nicht während der DNS-Lookup geehrt werden - die Sie umgehen können, indem Sie libcurl mit c-ares-Unterstützung erstellen. c-ares ist eine Bibliothek, die asynchronen Namen verrechnet. Auf einigen Plattformen funktioniert libcurl einfach nicht Funktion richtig multi-threaded , wenn diese Option festgelegt ist.

Beachten Sie auch, dass CURLOPT_DNS_USE_GLOBAL_CACHE nicht thread-safe ist.

+0

Ja, ich habe diesen Teil der Locke gelesen, und Mein Programm folgt allen Richtlinien von dort. Aber ich habe das Problem lokalisiert und es ist nicht der Fehler, es war nur Debugger zeigte dort. Ich habe ein paar neue Dinge über Curl gelernt, danke trotzdem. – Mogwai

0

Wie in error: longjmp causes uninitialized stack frame erwähnt, ist die neuesten Libcurl Versionen (> = 7.32.0) in Debian/Ubuntu-Repositories enthalten ein neues Multi-Thread-Resolver diese Probleme zu lösen. Die c-ares Unterstützung ist keine gute Lösung:

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

„Das eigentliche Problem ist, dass c-ares noch nicht ein vollwertiger Ersatz für gethostby ist * Funktionen (zB nicht Multicast-DNS nicht unterstützt) und ermöglichen es auf Lager libcurl Pakete möglicherweise nicht ein guter Zug (beachten Sie, dass dies Wörter des vorgelagerten Autors von beiden sind locken und c-ares, nicht meins). "-