2010-07-19 17 views
7

Así que tengo un montón de subprocesos de trabajo haciendo clase de rizo simple, cada subproceso de trabajador tiene su propio rizo fácil de manejar. Solo realizan búsquedas HEAD en sitios web aleatorios. También existen funciones de bloqueo para habilitar el SSL de múltiples hilos como se documenta en here. Todo está funcionando, excepto en 2 páginas web ilsole24ore.com (visto en el ejemplo abajo), y ninemsn.com.au/, a veces se producen seg averías, según se muestra en la salida de rastreo se muestra aquíError de segmentación en libcurl, multiproceso

#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 

Mi función se ve algo como este

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

Ahora, cuando llamo función sin hilos, simplemente llamando desde principal que nunca se rompe, por lo que estaba pensando en su conectados a los hilos, o tal vez la forma devuelven datos estructura se está devolviendo, pero por lo que see in trace parece que se genera un error en la llamada a easy_perform(), y me confunde. Así que si alguien tiene alguna idea de dónde debería mirar a continuación, sería de gran ayuda, gracias.

Respuesta

13

Hay una sección entera dedicada en libcurl to Multi-Threading.

La primera regla básica es que usted debe nunca comparta un mango libcurl (ya sea sencillos o múltiples o lo que sea) entre varios subprocesos. Solo use una manija en un hilo a la vez.

libcurl es completamente seguro para hilos, a excepción de dos problemas: señales y controladores SSL/TLS. Las señales se utilizan para resuelve el tiempo de espera (durante la búsqueda de DNS ) - cuando se construye sin compatibilidad con c-ares y no en Windows.

Si accede a HTTPS o FTPS URL de una manera multi-hilo, que está entonces por supuesto utilizando el subyacente SSL biblioteca multi-hilo y esas bibliotecas pueden tener sus propios requisitos sobre este tema. Básicamente, necesita proporcionar una o dos funciones para permitir que funcione correctamente . Para todos los detalles, ver esto:

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

se afirma que es seguro para subprocesos ya sin nada necesario.

yassl

Acciones necesarias desconocido.

Al usar varios hilos, debe establecer la opción CURLOPT_NOSIGNAL en 1 para todos los identificadores.Todo funcionará podría funcionar bien, excepto que los tiempos de espera no se respetan durante la búsqueda de DNS , que puede solucionar construyendo libcurl con soporte c-ares. c-ares es una biblioteca que proporciona resuelve el nombre asincrónico. En algunas plataformas , libcurl simplemente no funcionará correctamente a menos que se establezca esta opción.

Además, tenga en cuenta que CURLOPT_DNS_USE_GLOBAL_CACHE no es thread-safe.

+0

Sí, he leído esa parte de curl, y mi programa sigue todas las pautas desde allí. Pero he localizado el problema y no es culpa de los rizos, era solo que el depurador estaba apuntando allí. Aprendí algunas cosas nuevas sobre Curl, gracias de todos modos. – Mogwai

0

Como se mencionó en error: longjmp causes uninitialized stack frame, las últimas versiones libcurl (> = 7.32.0) en los repositorios de Debian/Ubuntu contienen una nueva resolución de multiproceso para resolver estos problemas. El soporte de c-ares no es una buena solución:

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

"El verdadero problema es que c-ares aún no es un reemplazo completo para gethostby * funciones (por ejemplo, que no soporta multicast DNS) y permitiendo en stock los paquetes de libcurl pueden no ser una buena jugada (tenga en cuenta que estas son palabras del autor principal de curl y c-ares, no mío). "-

Cuestiones relacionadas