问题
I conducted an experiment with DNS resolving by gethostbyname() from different threads. I turned off network link and ran program below. And output was like this
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() started at the same time, but finished one by one with 40 sec timeout.
Then i experemented with getaddrinfo(). And it looks like this function doesn't suffer from this problem
getaddrinfo started at 1411235759 getaddrinfo started at 1411235759 getaddrinfo started at 1411235759 getaddrinfo finished at 1411235799 getaddrinfo finished at 1411235799 getaddrinfo finished at 1411235799
So, why I got this result and is this behavior specific for Linux only?
#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:
The getaddrinfo()
function doesn't share any global/static variables and is thus reentrant an therefore thread-safe. It returns result in memory allocated using malloc()
and the user is responsible for using freeaddrinfo()
which in turn uses free()
to allocate the data. Therefore you are allowed to run getaddrinfo()
simultaneously from multiple threads and the the individual instances run in parallel.
On the other hand, gethostbyname()
returns a pointer to global/static data and thus is not reentrant. The user is not responsible for freeing the data. Therefore you are not allowed to run gethostbyname()
simultaneously from multiple threads. According to your tests, the GNU C library apparently serializes the calls to avoid errors resulting from the parallel run.
You should generally avoid using gethostbyname()
as it's somewhat obsoleted by getaddrinfo()
but the latter is not a perfect replacement, at least in glibc. I would recommend using getaddrinfo()
and employ workarounds for its bugs where appropriate.
You could find out more by examining the source code.
来源:https://stackoverflow.com/questions/25951925/gethostbyname-processes-resolving-consistently-even-from-different-threads