2010-07-19 4 views
7

J'ai donc un tas de threads de travail faisant une simple classe curl, chaque thread de travail a son propre handle facile. Ils ne font que des recherches HEAD sur des sites Web aléatoires. Des fonctions de verrouillage sont également présentes pour activer le protocole SSL multi-thread comme documenté here. Tout fonctionne, sauf sur 2 pages web ilsole24ore.com (vu dans l'exemple vers le bas), et ninemsn.com.au/, ils produisent parfois défaut seg comme le montre la sortie de trace montré iciErreur de segmentation dans 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 

Ma fonction ressemble ce

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

maintenant, quand j'appelle la fonction sans fils, simplement en l'appelant du principal il se casse jamais, donc je pensais de la connexion à des fils, ou peut-être comment la structure renvoient des données est retourné, mais de ce que je vu en trace, il semble que la faute soit générée dans l'appel easy_perform(), et sa confusion me. Donc, si quelqu'un a une idée d'où devrais-je regarder à côté, il serait très utile, merci.

Répondre

13

Il y a une section entière consacrée dans libcurl to Multi-Threading.

La première règle de base est que vous devez jamais partager une poignée de libcurl (que ce soit facile ou multi ou autre) entre plusieurs threads. Utilisez uniquement une poignée dans un fil à la fois.

libcurl est enfilez complètement sûr, sauf deux questions: les signaux et les gestionnaires SSL/TLS. Les signaux sont utilisés pour résout le nom résout (pendant DNS recherche) - lorsqu'il est construit sans support c-ares et pas sur Windows.

Si vous accédez à HTTPS ou FTPS URL d'une manière multi-thread, vous utilisent alors bien sûr la sous-jacente bibliothèque SSL multi-thread et les libs pourraient avoir leurs propres exigences sur cette question. Fondamentalement, vous devez fournir une ou deux fonctions pour lui permettre de fonctionner correctement . Pour tous les détails, voir ceci:

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

est prétendu être thread-safe déjà sans rien nécessaire.

yassl

Actions requises inconnues. Lorsque vous utilisez plusieurs threads, définissez l'option CURLOPT_NOSIGNAL sur 1 pour toutes les poignées.Tout peut ou peut fonctionner correctement, sauf que les délais ne sont pas respectés lors de la recherche DNS - que vous pouvez contourner en créant libcurl avec le support c-ares. c-ares est une bibliothèque qui fournit des résolutions de noms asynchrones . Sur certaines plates-formes , libcurl ne fonctionnera pas correctement correctement multi-thread sauf si cette option est définie.

Notez également que CURLOPT_DNS_USE_GLOBAL_CACHE n'est pas thread-safe.

+0

Ouais, j'ai lu cette partie de curl, et mon programme suit toutes les directives à partir de là. Mais j'ai localisé le problème et sa faute n'est pas les boucles, c'était juste le débogueur pointait là. J'ai appris quelques nouvelles choses sur curl, merci quand même. – Mogwai

0

Comme mentionné dans error: longjmp causes uninitialized stack frame, les dernières versions de libcurl (> = 7.32.0) dans les dépôts Debian/Ubuntu contiennent un nouveau résolveur multithread pour résoudre ces problèmes. Le c-ares soutien n'est pas une bonne solution:

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

« Le vrai problème est que c-ares n'est pas encore un remplacement complet pour gethostby * fonctions (par exemple, il ne prend pas en charge DNS multicast) et permettant il en stock libcurl paquets ne peut pas être un bon coup (notez que ce sont les mots de l'auteur en amont de curl et c-ares, pas le mien). "-