gethostbyname()进程甚至从不同的线程一致地解决?

时间:2014-09-20 18:18:43

标签: c linux multithreading gethostbyname

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

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

1 个答案:

答案 0 :(得分:3)

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

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

您通常应该避免使用getaddrinfo(),因为它getaddrinfo()有点过时,但后者是not a perfect replacement,至少在glibc中。我建议使用{{1}}并在适当的地方使用变通方法。

您可以通过检查源代码找到更多信息。