有几个要注意的:
1. getaddrinfo可能阻塞一段时间 , 这里给了一种简便方法来处理它
2. 参数的传递, 除了要解析的域名这类参数, 把父线程ID也传给它, 当解析成功发现父线程已退出, 直接释放结果 退出, 不用返回数据了, 避免内存泄漏
3. 如何返回解析的结果给父线程 并输出打印
4. 父线程 如何等待子线程退出并获取结果 又或者 如何放任子线程自生自灭.
直接上代码, 里面有注释, 已编译运行测试过:
-
#include <stdio.h>
-
#include <string.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <time.h>
-
#include <pthread.h>
-
#include <signal.h>
-
#include <errno.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <arpa/inet.h>
-
#include <netdb.h>
-
-
/*pthread_kill的返回值:成功(0) 线程不存在(ESRCH) 信号不合法(EINVAL)*/
-
enum {
-
PTHREAD_RET_ALIVE = 1,
-
PTHREAD_RET_ESRCH,
-
PTHREAD_RET_EINVAL,
-
};
-
-
static int pthread_test(pthread_t tid)
-
{
-
int pthread_kill_err;
-
pthread_kill_err = pthread_kill(tid,0);
-
-
if(pthread_kill_err == ESRCH) {
-
printf("ID为0x%x的线程不存在或者已经退出。\n",(unsigned int)tid);
-
return PTHREAD_RET_ESRCH;
-
}
-
else if(pthread_kill_err == EINVAL) {
-
printf("发送信号非法。/n");
-
return PTHREAD_RET_EINVAL;
-
}
-
-
printf("ID为0x%x的线程目前仍然存活。\n",(unsigned int)tid);
-
return PTHREAD_RET_ALIVE;
-
}
-
#define pthread_is_alive(tid) (pthread_test(tid) != PTHREAD_RET_ESRCH)
-
-
static inline int pthread_t_is_zero(pthread_t tid)
-
{
-
pthread_t zero_tid;
-
memset(&zero_tid, 0, sizeof(zero_tid));
-
-
return !memcmp(&tid, &zero_tid, sizeof(pthread_t));
-
}
-
-
typedef void* thread_fun(void *);
-
static pthread_t pthread_start(thread_fun func, void *arg)
-
{
-
pthread_t tid;
-
int ret = 0;
-
-
pthread_attr_t attr;
-
pthread_attr_init(&attr);
-
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
-
-
memset(&tid, 0, sizeof(tid));
-
-
ret = pthread_create(&tid, &attr, func, arg);
-
if (ret != 0) {
-
memset(&tid, 0, sizeof(tid));
-
}
-
-
return tid;
-
}
-
-
typedef struct st_addrinfoparas_struct {
-
pthread_t p_tid;
-
char url[128];
-
char port[32];
-
struct addrinfo hint;
-
}st_addrinfoparas;
-
-
void* thread_getaddrinfo(void *arg)
-
{
-
st_addrinfoparas *input = (st_addrinfoparas*)arg;
-
struct addrinfo hints;
-
struct addrinfo* res = NULL;
-
-
/* 禁止 被pthread_cancel()中途中止 */
-
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
-
if (!input)
-
pthread_exit(NULL);
-
-
hints.ai_socktype = input->hint.ai_socktype;
-
hints.ai_protocol = input->hint.ai_protocol;
-
hints.ai_flags = input->hint.ai_flags;
-
hints.ai_family = input->hint.ai_family;
-
-
/* getaddrinfo 也许会阻塞很长时间 */
-
int ret = getaddrinfo (input->url, input->port, &hints, &res);
-
if (0 != ret) {
-
printf("getaddrinfo url[%s] port[%s] failed: %s\n", input->url, input->port, gai_strerror(ret));
-
goto exit;
-
-
}
-
-
/* 父进程已经退出了? 那么不需要将结果返回了 直接释放了吧. */
-
if (!pthread_t_is_zero(input->p_tid)) {
-
if (!pthread_is_alive(input->p_tid)) {
-
freeaddrinfo(res);
-
res = NULL;
-
}
-
}
-
-
exit:
-
-
/* 父进程分配的动态内存用来传递参数
-
* 我们应该负责释放它
-
* */
-
if (input)
-
free(input);
-
-
pthread_exit(res);
-
}
-
-
int my_test_getaddrinfo(char *url, char *port)
-
{
-
int no_wait = 0;
-
int ret;
-
pthread_t tid;
-
struct addrinfo *res = NULL, *rp = NULL;
-
st_addrinfoparas *p_para = NULL;
-
struct sockaddr_in *sinp;
-
char ip[128] = {0};
-
-
p_para = (st_addrinfoparas *)calloc(1, sizeof(st_addrinfoparas));
-
p_para->p_tid = pthread_self();
-
if (url)
-
strcpy(p_para->url, url);
-
if (port)
-
strcpy(p_para->port, port);
-
p_para->hint.ai_socktype = SOCK_STREAM;
-
p_para->hint.ai_protocol = IPPROTO_TCP;
-
p_para->hint.ai_flags = 0;
-
p_para->hint.ai_family = AF_INET;
-
-
tid = pthread_start(thread_getaddrinfo, (void *)p_para);
-
if (!pthread_t_is_zero(tid)) {
-
while (1) {
-
if (!pthread_is_alive(tid)) {
-
pthread_join(tid, (void **)&res);
-
if (res) {
-
if (res == PTHREAD_CANCELED) {
-
printf("ID为0x%x的线程被CANCEL终止\n", (unsigned int)tid);
-
}
-
else {
-
printf("获取ID为0x%x的线程结果: %p\n", (unsigned int)tid, res);
-
for (rp = res; rp != NULL; rp = rp->ai_next) {
-
sinp = (struct sockaddr_in *)rp->ai_addr;
-
printf("getaddrinfo result: ip[%s] addrlen[%d] flags[%d] family[%d] ai_socktype[%d] protocol[%d]\n",
-
inet_ntop(rp->ai_family, &sinp->sin_addr, ip, sizeof(ip)), rp->ai_addrlen, rp->ai_flags, rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-
}
-
-
freeaddrinfo(res);
-
}
-
}
-
break;
-
}
-
else if (no_wait) {
-
/* 如果不想等待子线程了 可以直接detach 然后退出
-
* 让子线程自己超时退出 系统回收其资源
-
* 当然动态分配的空间还是需要我们手动释放的,具体看子线程 代码.
-
*/
-
pthread_detach(tid);
-
break;
-
}
-
else {
-
/* 过一秒循环查看一次子线程是否退出 */
-
sleep(1);
-
}
-
}
-
memset(&tid, 0, sizeof(tid));
-
}
-
-
return 0;
-
}
-
-
int main(int argc,char *argv[])
-
{
-
my_test_getaddrinfo(argv[1], argv[2]);
-
-
return 0;
-
}
拷贝到test.c文件中编译: cc test.c -o test -lpthread
运行: ./test 80
-
[root@/tmp]# ./test www.baidu.com 80
-
ID为0x992b6700的线程目前仍然存活。
-
ID为0x99a93700的线程目前仍然存活。
-
ID为0x992b6700的线程不存在或者已经退出。
-
获取ID为0x992b6700的线程结果:
-
getaddrinfo result: ip[61.135.169.125] addrlen[16] flags[0] family[2] ai_socktype[1] protocol[6]
-
getaddrinfo result: ip[61.135.169.121] addrlen[16] flags[0] family[2] ai_socktype[1] protocol[6]
阅读(2267) | 评论(0) | 转发(0) |