2

我通过不同线程的 gethostbyname() 进行了 DNS 解析实验。我关闭了网络链接并在下面运行程序。输出是这样的

gethostbyname 开始于 1411234734
gethostbyname 开始于 1411234734
gethostbyname 开始于 1411234734
gethostbyname 完成于 1411234774
gethostbyname 完成于 1411234814
gethostbyname 完成于 1411234854

gethostbyname() 同时开始,但在 40 秒超时后一一结束。

然后我用 getaddrinfo() 进行了实验。看起来这个函数没有这个问题

getaddrinfo 开始于 1411235759
getaddrinfo 开始于 1411235759
getaddrinfo 开始于 1411235759
getaddrinfo 完成于 1411235799
getaddrinfo 完成于 1411235799
getaddrinfo 完成于 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;
}
4

1 回答 1

4

getaddrinfo()函数不共享任何全局/静态变量,因此是可重入的,因此是线程安全的。它在分配的内存中返回结果,malloc()用户负责使用freeaddrinfo()free()来分配数据。因此,您可以getaddrinfo()从多个线程同时运行,并且各个实例并行运行。

另一方面,gethostbyname()返回指向全局/静态数据的指针,因此不可重入。用户不负责释放数据。因此,您不允许gethostbyname()从多个线程同时运行。根据您的测试,GNU C 库显然会序列化调用以避免并行运行导致的错误。

您通常应该避免使用gethostbyname()它,因为它已经过时了,getaddrinfo()但后者并不是一个完美的替代品,至少在 glibc 中是这样。我建议getaddrinfo()在适当的情况下使用和使用解决方法来解决它的错误。

您可以通过查看源代码了解更多信息。

于 2014-09-20T18:35:03.900 回答