2014-09-20 5 views
1

다른 스레드에서 gethostbyname()을 사용하여 DNS를 해결하는 실험을 수행했습니다. 나는 아래의 네트워크 링크를 끄고 프로그램을 실행했다. 출력은 다음과 같습니다.gethostbyname() 프로세스가 다른 스레드에서도 일관되게 해결됩니까?

 
gethostbyname started at 1411234734 
gethostbyname started at 1411234734 
gethostbyname started at 1411234734 
gethostbyname finished at 1411234774 
gethostbyname finished at 1411234814 
gethostbyname finished at 1411234854 

gethostbyname()이 동시에 시작되었지만 40 초의 시간 초과로 하나씩 완료되었습니다.

그런 다음 getaddrinfo()를 사용하여 확장되었습니다. 그리고이 함수가이 문제를 겪지 않는 것처럼 보입니다.

 
getaddrinfo started at 1411235759 
getaddrinfo started at 1411235759 
getaddrinfo started at 1411235759 
getaddrinfo finished at 1411235799 
getaddrinfo finished at 1411235799 
getaddrinfo finished at 1411235799 

그렇다면 왜이 결과를 얻었 을까요?이 동작은 Linux에만 해당되는 것입니까?

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <time.h> 
#include <pthread.h> 

void *resolve_ghbn(void *host) { 
    printf("gethostbyname started at %d\n", time(NULL)); 
    struct hostent *rslv = gethostbyname((char*)host); 
    printf("gethostbyname finished at %d\n", time(NULL)); 

    return NULL; 
} 

void *resolve_gai(void *host) { 
    struct addrinfo *result; 
    printf("getaddrinfo started at %d\n", time(NULL)); 
    int res = getaddrinfo(host, NULL, NULL, &result); 
    printf("getaddrinfo finished at %d\n", time(NULL)); 
    if (res == 0) 
     freeaddrinfo(result); 

    return NULL; 
} 

int main() { 
    char *domains[] = {"google.com", "google.cy", "google.us"}; 
    pthread_t threads[3]; 
    int i; 

    for (i=0; i<3; i++) { 
     pthread_create(&threads[i], NULL, resolve_ghbn, domains[i]); 
    } 

    void *retval; 

    for (i=0; i<3; i++) { 
     pthread_join(threads[i], &retval); 
    } 

    return 0; 
} 
+2

'getaddrinfo()'를 사용하거나 전역 뮤텍스를 사용하십시오. 행동의 차이점은 무엇입니까? 두 경우 모두 40 초의 시간 초과가 발생하며 네트워크 링크를 끄는 방법과 해제 된 방법을 확인하는 방법이 있습니까? –

+0

이봐, 이제 알 겠어. 나는 대답을 준비 할 것이다. –

답변

3

getaddrinfo() 함수가 전역/정적 변수를 공유하지 않으며, 따라서, 따라서 스레드 안전 재진입. malloc()을 사용하여 할당 된 메모리에 결과를 반환하며 freeaddrinfo()을 사용하고 다시 free()을 사용하여 데이터를 할당해야합니다. 따라서 getaddrinfo()을 여러 스레드에서 동시에 실행하고 개별 인스턴스를 병렬로 실행할 수 있습니다.

한편, gethostbyname()은 글로벌/정적 데이터에 대한 포인터를 반환하므로 is not reentrant입니다. 사용자는 데이터를 해제 할 책임이 없습니다. 그러므로 이 복수 스레드에서 동시에 gethostbyname()을 실행할 수 없습니다. 테스트 결과에 따르면 GNU C 라이브러리는 병렬 실행으로 인한 오류를 피하기 위해 호출을 직렬화합니다.

일반적으로 getaddrinfo()으로 다소 폐기 된 gethostbyname()은 사용하지 말아야하지만 후자는 적어도 glibc에서는 not a perfect replacement입니다. getaddrinfo()을 사용하고 해당 버그에 대한 해결 방법을 사용하는 것이 좋습니다.

소스 코드를 살펴보면 더 많은 것을 알 수 있습니다.