免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2110 | 回复: 6

[C] 这个线程池的程序,为什么会出现内存错误呢?是 malloc的原因吗 [复制链接]

论坛徽章:
0
发表于 2012-12-06 10:22 |显示全部楼层
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <pthread.h>
  6. #include <assert.h>

  7. /*
  8. *线程池里所有运行和等待的任务都是一个CThread_worker
  9. *由于所有任务都在链表里,所以是一个链表结构
  10. */
  11. typedef struct worker
  12. {
  13.     /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/
  14.     void *(*process) (void *arg);
  15.     void *arg;/*回调函数的参数*/
  16.     struct worker *next;
  17. } CThread_worker;

  18. /*线程池结构*/
  19. typedef struct
  20. {
  21.     pthread_mutex_t queue_lock;
  22.     pthread_cond_t queue_ready;

  23.     /*链表结构,线程池中所有等待任务*/
  24.      CThread_worker *queue_head;
  25.     /*是否销毁线程池*/
  26.     int shutdown;
  27.     pthread_t *threadid;
  28.     /*线程池中允许的活动线程数目*/
  29.     int max_thread_num;
  30.     /*当前等待队列的任务数目*/
  31.     int cur_queue_size;
  32. } CThread_pool;

  33. int pool_add_worker (void *(*process) (void *arg), void *arg);
  34. void *thread_routine (void *arg);
  35. static CThread_pool *pool = NULL;

  36. void pool_init (int max_thread_num)
  37. {
  38.      pool = (CThread_pool *) malloc (sizeof (CThread_pool));

  39.      pthread_mutex_init (&(pool->queue_lock), NULL);
  40.      pthread_cond_init (&(pool->queue_ready), NULL);

  41.      pool->queue_head = NULL;

  42.      pool->max_thread_num = max_thread_num;
  43.      pool->cur_queue_size = 0;

  44.      pool->shutdown = 0;

  45.      pool->threadid =  (pthread_t *) malloc (max_thread_num * sizeof (pthread_t));
  46.      int i = 0;
  47.      for (i = 0; i < max_thread_num; i++)
  48.      {
  49.          pthread_create (&(pool->threadid[i]), NULL, thread_routine,
  50.                  NULL);
  51.      }
  52. }

  53. /*向线程池中加入任务*/
  54. int  pool_add_worker (void *(*process) (void *arg), void *arg)
  55. {
  56.     /*构造一个新任务*/
  57.      CThread_worker *newworker =
  58.          (CThread_worker *) malloc (sizeof (CThread_worker));
  59.      newworker->process = process;
  60.      newworker->arg = arg;
  61.      newworker->next = NULL;/*别忘置空*/

  62.      pthread_mutex_lock (&(pool->queue_lock));
  63.     /*将任务加入到等待队列中*/
  64.      CThread_worker *member = pool->queue_head;
  65.     if (member != NULL)
  66.      {
  67.         while (member->next != NULL)
  68.              member = member->next;
  69.          member->next = newworker;
  70.      }
  71.     else
  72.      {
  73.          pool->queue_head = newworker;
  74.      }

  75.      assert (pool->queue_head != NULL);
  76.      pool->cur_queue_size++;
  77.      pthread_mutex_unlock (&(pool->queue_lock));
  78.     /*好了,等待队列中有任务了,唤醒一个等待线程;
  79.      注意如果所有线程都在忙碌,这句没有任何作用*/
  80.      pthread_cond_signal (&(pool->queue_ready));
  81.     return 0;
  82. }

  83. /*销毁线程池,等待队列中的任务不会再被执行,但是正在运行的线程会一直
  84. 把任务运行完后再退出*/
  85. int
  86. pool_destroy ()
  87. {
  88.     if (pool->shutdown)
  89.         return -1;/*防止两次调用*/
  90.      pool->shutdown = 1;


  91.     /*唤醒所有等待线程,线程池要销毁了*/
  92.      pthread_cond_broadcast (&(pool->queue_ready));


  93.     /*阻塞等待线程退出,否则就成僵尸了*/
  94.     int i;
  95.     for (i = 0; i < pool->max_thread_num; i++)
  96.          pthread_join (pool->threadid[i], NULL);
  97.      free (pool->threadid);


  98.     /*销毁等待队列*/
  99.      CThread_worker *head = NULL;
  100.     while (pool->queue_head != NULL)
  101.      {
  102.          head = pool->queue_head;
  103.          pool->queue_head = pool->queue_head->next;
  104.          free (head);
  105.      }
  106.     /*条件变量和互斥量也别忘了销毁*/
  107.      pthread_mutex_destroy(&(pool->queue_lock));
  108.      pthread_cond_destroy(&(pool->queue_ready));
  109.      
  110.      free (pool);
  111.     /*销毁后指针置空是个好习惯*/
  112.      pool=NULL;
  113.     return 0;
  114. }

  115. void *thread_routine (void *arg)
  116. {
  117.     printf ("starting thread 0x%x\n", pthread_self ());
  118.     while (1)
  119.     {
  120.         pthread_mutex_lock (&(pool->queue_lock));
  121.         /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意
  122.              pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/
  123.         while (pool->cur_queue_size == 0 && !pool->shutdown)
  124.         {
  125.              printf ("thread 0x%x is waiting\n", pthread_self ());
  126.              pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));
  127.         }

  128.         /*线程池要销毁了*/
  129.         if (pool->shutdown)
  130.          {
  131.             /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/
  132.              pthread_mutex_unlock (&(pool->queue_lock));
  133.              printf ("thread 0x%x will exit\n", pthread_self ());
  134.              pthread_exit (NULL);
  135.          }

  136.          printf ("thread 0x%x is starting to work\n", pthread_self ());


  137.         /*assert是调试的好帮手*/
  138.          assert (pool->cur_queue_size != 0);
  139.          assert (pool->queue_head != NULL);
  140.          
  141.         /*等待队列长度减去1,并取出链表中的头元素*/
  142.          pool->cur_queue_size--;
  143.          CThread_worker *worker = pool->queue_head;
  144.          pool->queue_head = worker->next;
  145.          pthread_mutex_unlock (&(pool->queue_lock));

  146.         /*调用回调函数,执行任务*/
  147.          (*(worker->process)) (worker->arg);
  148.          free (worker);
  149.          worker = NULL;
  150.      }
  151.       /*这一句应该是不可达的*/
  152.      pthread_exit (NULL);
  153. }


  154. void *  myprocess (void *arg)
  155. {
  156.     printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);
  157.     usleep (50);/*休息一秒,延长任务的执行时间*/
  158.     return NULL;
  159. }

  160. int main (int argc, char **argv)
  161. {
  162.     pool_init (5);/*线程池中最多三个活动线程*/
  163.      
  164.     /*连续向池中投入10个任务*/
  165.     int *workingnum = (int *) malloc (sizeof (int) * 10);
  166.     int i;
  167.     for (i = 0; i < atoi(argv[1]); i++)
  168.     {
  169.          workingnum[i] = i;
  170.          pool_add_worker (myprocess, &workingnum[i]);
  171.     }
  172.     /*等待所有任务完成*/
  173.     sleep (5);
  174.     /*销毁线程池*/
  175.     pool_destroy ();
  176.     free (workingnum);
  177.     return 0;
  178. }

复制代码

论坛徽章:
0
发表于 2012-12-06 11:04 |显示全部楼层
线程池,有点复杂,好像没人帮你呀

论坛徽章:
0
发表于 2012-12-06 11:25 |显示全部楼层
回复 2# fenghw8088


  自己解决了,哈哈。
  犯了一个小错。。。代码中 线程池的设计是没有问题的。

论坛徽章:
0
发表于 2012-12-06 14:20 |显示全部楼层
因为这个程序后面需要加一个参数,表示要添加的任务数量
所以有两个办法:
1、在运行可执行程序时加一个参数 ,如  ./pool 10
2、你可以选择把程序中的argv[1]换成10 或者其他数字

论坛徽章:
0
发表于 2012-12-06 16:08 |显示全部楼层
回复 4# Tiodnaci


    谢谢你。 问题解决了

论坛徽章:
26
处女座
日期:2016-04-18 14:00:4515-16赛季CBA联赛之深圳
日期:2020-06-02 10:10:5015-16赛季CBA联赛之广夏
日期:2019-07-23 16:59:452016科比退役纪念章
日期:2019-06-26 16:59:1315-16赛季CBA联赛之天津
日期:2019-05-28 14:25:1915-16赛季CBA联赛之青岛
日期:2019-05-16 10:14:082016科比退役纪念章
日期:2019-01-11 14:44:062016科比退役纪念章
日期:2018-07-18 16:17:4015-16赛季CBA联赛之上海
日期:2017-08-22 18:18:5515-16赛季CBA联赛之江苏
日期:2017-08-04 17:00:4715-16赛季CBA联赛之佛山
日期:2017-02-20 18:21:1315-16赛季CBA联赛之天津
日期:2016-12-12 10:44:23
发表于 2012-12-06 16:29 |显示全部楼层
解决了分享下啊 怎么解决的 问题在哪里 ?

论坛徽章:
0
发表于 2012-12-06 21:03 |显示全部楼层
回复 6# evaspring


    就是 四楼 说的那样
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP