Chinaunix首页 | 论坛 | 博客
  • 博客访问: 63352
  • 博文数量: 7
  • 博客积分: 90
  • 博客等级: 民兵
  • 技术积分: 117
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-26 09:09
文章分类

全部博文(7)

文章存档

2018年(1)

2017年(4)

2012年(2)

我的朋友

分类: C/C++

2017-09-26 14:46:15


   有几个要注意的:
        1. getaddrinfo可能阻塞一段时间 , 这里给了一种简便方法来处理它
        2. 参数的传递, 除了要解析的域名这类参数, 把父线程ID也传给它, 当解析成功发现父线程已退出, 直接释放结果 退出, 不用返回数据了, 避免内存泄漏
        3. 如何返回解析的结果给父线程 并输出打印
        4. 父线程 如何等待子线程退出并获取结果  又或者  如何放任子线程自生自灭.

   直接上代码, 里面有注释, 已编译运行测试过:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <time.h>
  6. #include <pthread.h>
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <arpa/inet.h>
  12. #include <netdb.h>

  13. /*pthread_kill的返回值:成功(0) 线程不存在(ESRCH) 信号不合法(EINVAL)*/
  14. enum {
  15.     PTHREAD_RET_ALIVE = 1,
  16.     PTHREAD_RET_ESRCH,
  17.     PTHREAD_RET_EINVAL,
  18. };

  19. static int pthread_test(pthread_t tid)
  20. {
  21.     int pthread_kill_err;
  22.     pthread_kill_err = pthread_kill(tid,0);

  23.     if(pthread_kill_err == ESRCH) {
  24.         printf("ID为0x%x的线程不存在或者已经退出。\n",(unsigned int)tid);
  25.         return PTHREAD_RET_ESRCH;
  26.     }
  27.     else if(pthread_kill_err == EINVAL) {
  28.         printf("发送信号非法。/n");
  29.         return PTHREAD_RET_EINVAL;
  30.     }

  31.     printf("ID为0x%x的线程目前仍然存活。\n",(unsigned int)tid);
  32.     return PTHREAD_RET_ALIVE;
  33. }
  34. #define pthread_is_alive(tid) (pthread_test(tid) != PTHREAD_RET_ESRCH)

  35. static inline int pthread_t_is_zero(pthread_t tid)
  36. {
  37.     pthread_t zero_tid;
  38.     memset(&zero_tid, 0, sizeof(zero_tid));

  39.     return !memcmp(&tid, &zero_tid, sizeof(pthread_t));
  40. }

  41. typedef void* thread_fun(void *);
  42. static pthread_t pthread_start(thread_fun func, void *arg)
  43. {
  44.     pthread_t tid;
  45.     int ret = 0;

  46.     pthread_attr_t attr;
  47.     pthread_attr_init(&attr);
  48.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);


  49.     memset(&tid, 0, sizeof(tid));

  50.     ret = pthread_create(&tid, &attr, func, arg);
  51.     if (ret != 0) {
  52.         memset(&tid, 0, sizeof(tid));
  53.     }

  54.     return tid;
  55. }

  56. typedef struct st_addrinfoparas_struct {
  57.     pthread_t p_tid;
  58.     char url[128];
  59.     char port[32];
  60.     struct addrinfo hint;
  61. }st_addrinfoparas;

  62. void* thread_getaddrinfo(void *arg)
  63. {
  64.     st_addrinfoparas *input = (st_addrinfoparas*)arg;
  65.     struct addrinfo hints;
  66.     struct addrinfo* res = NULL;

  67.     /* 禁止 被pthread_cancel()中途中止 */
  68.     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

  69.     if (!input)
  70.         pthread_exit(NULL);

  71.     hints.ai_socktype = input->hint.ai_socktype;
  72.     hints.ai_protocol = input->hint.ai_protocol;
  73.     hints.ai_flags = input->hint.ai_flags;
  74.     hints.ai_family = input->hint.ai_family;

  75.     /* getaddrinfo 也许会阻塞很长时间 */
  76.     int ret = getaddrinfo (input->url, input->port, &hints, &res);
  77.     if (0 != ret) {
  78.         printf("getaddrinfo url[%s] port[%s] failed: %s\n", input->url, input->port, gai_strerror(ret));
  79.         goto exit;

  80.     }

  81.     /* 父进程已经退出了? 那么不需要将结果返回了 直接释放了吧. */
  82.     if (!pthread_t_is_zero(input->p_tid)) {
  83.         if (!pthread_is_alive(input->p_tid)) {
  84.             freeaddrinfo(res);
  85.             res = NULL;
  86.         }
  87.     }

  88. exit:

  89.     /* 父进程分配的动态内存用来传递参数
  90.      * 我们应该负责释放它
  91.      * */
  92.     if (input)
  93.         free(input);

  94.     pthread_exit(res);
  95. }

  96. int my_test_getaddrinfo(char *url, char *port)
  97. {
  98.     int no_wait = 0;
  99.     int ret;
  100.     pthread_t tid;
  101.     struct addrinfo *res = NULL, *rp = NULL;
  102.     st_addrinfoparas *p_para = NULL;
  103.     struct sockaddr_in *sinp;
  104.     char ip[128] = {0};

  105.     p_para = (st_addrinfoparas *)calloc(1, sizeof(st_addrinfoparas));
  106.     p_para->p_tid = pthread_self();
  107.     if (url)
  108.         strcpy(p_para->url, url);
  109.     if (port)
  110.         strcpy(p_para->port, port);
  111.     p_para->hint.ai_socktype = SOCK_STREAM;
  112.     p_para->hint.ai_protocol = IPPROTO_TCP;
  113.     p_para->hint.ai_flags = 0;
  114.     p_para->hint.ai_family = AF_INET;

  115.     tid = pthread_start(thread_getaddrinfo, (void *)p_para);
  116.     if (!pthread_t_is_zero(tid)) {
  117.         while (1) {
  118.             if (!pthread_is_alive(tid)) {
  119.                 pthread_join(tid, (void **)&res);
  120.                 if (res) {
  121.                     if (res == PTHREAD_CANCELED) {
  122.                         printf("ID为0x%x的线程被CANCEL终止\n", (unsigned int)tid);
  123.                     }
  124.                     else {
  125.                         printf("获取ID为0x%x的线程结果: %p\n", (unsigned int)tid, res);
  126.                         for (rp = res; rp != NULL; rp = rp->ai_next) {
  127.                             sinp = (struct sockaddr_in *)rp->ai_addr;
  128.                             printf("getaddrinfo result: ip[%s] addrlen[%d] flags[%d] family[%d] ai_socktype[%d] protocol[%d]\n",
  129.                                     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);
  130.                         }

  131.                         freeaddrinfo(res);
  132.                     }
  133.                 }
  134.                 break;
  135.             }
  136.             else if (no_wait) {
  137.                 /* 如果不想等待子线程了 可以直接detach 然后退出
  138.                  * 让子线程自己超时退出 系统回收其资源
  139.                  * 当然动态分配的空间还是需要我们手动释放的,具体看子线程 代码.
  140.                  */
  141.                 pthread_detach(tid);
  142.                 break;
  143.             }
  144.             else {
  145.                 /* 过一秒循环查看一次子线程是否退出 */
  146.                 sleep(1);
  147.             }
  148.         }
  149.         memset(&tid, 0, sizeof(tid));
  150.     }

  151.     return 0;
  152. }

  153. int main(int argc,char *argv[])
  154. {
  155.     my_test_getaddrinfo(argv[1], argv[2]);

  156.     return 0;
  157. }

   拷贝到test.c文件中编译:  cc test.c -o test -lpthread
   运行:  ./test 80

点击(此处)折叠或打开

  1. [root@/tmp]# ./test www.baidu.com 80
  2. ID为0x992b6700的线程目前仍然存活。
  3. ID为0x99a93700的线程目前仍然存活。
  4. ID为0x992b6700的线程不存在或者已经退出。
  5. 获取ID为0x992b6700的线程结果:
  6. getaddrinfo result: ip[61.135.169.125] addrlen[16] flags[0] family[2] ai_socktype[1] protocol[6]
  7. getaddrinfo result: ip[61.135.169.121] addrlen[16] flags[0] family[2] ai_socktype[1] protocol[6]




阅读(2267) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~