c语言与线程池是什么关系?

mmzhzjia 2013-08-21 04:39:32

在网上找了关于线程池概念;找到了一下答案,但是还是闹不几米!

一:你手里有一个馒头,还有几条狗,你把馒头丢出去,哪条狗抢到算哪条的。
二:你把所有的狗都围起来了。然后你挑一条狗出来,然后把馒头给他。
...全文
730 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2013-08-22
  • 打赏
  • 举报
回复
引用 11 楼 ananluowei 的回复:
线程池的作用正是在这种情况下有效的降低频繁创建销毁线程所带来的额外开销。一般来说,线程池都是采用预创建的技术,在应用启动之初便预先创建一定数目的线程。应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。如果线程池中预先分配的线程已经全部分配完毕,但此时又有新的任务请求,则线程池会动态的创建新的线程去适应这个请求。当然,有可能,某些时段应用并不需要执行很多的任务,导致了线程池中的线程大多处于空闲的状态,为了节省系统资源,线程池就需要动态的销毁其中的一部分空闲线程。因此,线程池都需要一个管理者,按照一定的要求去动态的维护其中线程的数目。 我对红字部分有异议。 线程开太多没用处,cpu个数是一定的,开再多的线程也不会提高处理速度,反而增加了线程频繁切换以及线程同步付出的时间代价。 任务来不及做,多开线程就来得及了?表面上看起来是有个线程把任务接过去了,实际上其他线程执行他们的任务所需的时间变长了。 当然也有特殊情况,每个任务的时间都比较长,而用户需要“实时”的获取任务执行过程中的一些信息,这个时候是需要增加线程的。但是这种特殊情况,都是自己做特定的线程池,通用的线程池不适用。 我认为线程池开的时候几个就几个,中间去调整数量,这样的功能并不太实用。 以上是我个人的一些理解。
对内存管理我也持相似观点:
//使用动态分配
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int i,L;
char *p;
void main() {
    for (i=0;i<20000;i++) {
        L=rand();
        p=malloc(L);
        if (NULL==p) {
            printf("malloc error!\n");
            continue;
        }
        memset(p,0,L);
        free(p);
    }
}
//不使用动态分配
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define MAXLEN 30000
int i,L;
char buf[MAXLEN];
char *p;
void main() {
    p=&buf[0];
    for (i=0;i<20000;i++) {
        L=rand();
        if (L>MAXLEN) {
            printf("L>MAXLEN==%d, ignore spilth.\n",MAXLEN);
            L=MAXLEN;
        }
        memset(p,0,L);
    }
}
个人倾向“不使用动态分配”
u0116snail 2013-08-22
  • 打赏
  • 举报
回复
赞同11楼的观点
大尾巴猫 2013-08-21
  • 打赏
  • 举报
回复
线程池的作用正是在这种情况下有效的降低频繁创建销毁线程所带来的额外开销。一般来说,线程池都是采用预创建的技术,在应用启动之初便预先创建一定数目的线程。应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。如果线程池中预先分配的线程已经全部分配完毕,但此时又有新的任务请求,则线程池会动态的创建新的线程去适应这个请求。当然,有可能,某些时段应用并不需要执行很多的任务,导致了线程池中的线程大多处于空闲的状态,为了节省系统资源,线程池就需要动态的销毁其中的一部分空闲线程。因此,线程池都需要一个管理者,按照一定的要求去动态的维护其中线程的数目。 我对红字部分有异议。 线程开太多没用处,cpu个数是一定的,开再多的线程也不会提高处理速度,反而增加了线程频繁切换以及线程同步付出的时间代价。 任务来不及做,多开线程就来得及了?表面上看起来是有个线程把任务接过去了,实际上其他线程执行他们的任务所需的时间变长了。 当然也有特殊情况,每个任务的时间都比较长,而用户需要“实时”的获取任务执行过程中的一些信息,这个时候是需要增加线程的。但是这种特殊情况,都是自己做特定的线程池,通用的线程池不适用。 我认为线程池开的时候几个就几个,中间去调整数量,这样的功能并不太实用。 以上是我个人的一些理解。
赵4老师 2013-08-21
  • 打赏
  • 举报
回复
一:主程序和线程池中每个不忙的线程在同一个临界区内:主程序通知有新任务,等待某个线程领走并通知已无新任务,线程各自判断主程序是否有新任务,有就将自己置忙,通知主程序已无新任务,自己开始新任务。 二:主程序和线程池中不忙的线程在同一个临界区内:主程序逐一判断空闲的线程并按照一定策略把任务给某个线程并置忙,记录已无新任务;线程发现自己被置忙就去忙着完成新任务。
赵4老师 2013-08-21
  • 打赏
  • 举报
回复
引用 6 楼 mmzhzjia 的回复:
[quote=引用 5 楼 zhao4zhong1 的回复:] 领导有一项任务,还有几个手下: 一:领导开会通知不忙的手下,哪个手下抢到就由哪个手下完成。 二:领导挑一个不忙的手下出来,然后把任务给他。
亲 跟线程池对应一下该怎么说呢[/quote] 一:线程池中每个不忙的线程在同一个临界区内各自判断主程序是否有新任务,有就将自己置忙,通知主程序已无新任务,自己开始新任务。 二:主程序和线程池中不忙的线程在同一个临界区内:领导逐一判断空闲的线程并按照一定策略把任务给某个线程并置忙,记录已无新任务;线程发现自己被置忙就去忙着完成新任务。
mmzhzjia 2013-08-21
  • 打赏
  • 举报
回复
文章来源说 feige2008 linux下C语言使用线程池(附带编码) 分类: C 2012-08-03 16:23 318人阅读 评论(4) 收藏 举报 linux语言threadc任务null 本人也是学习,希望多多指正 使用一个东西,我们要明白为什么使用它,如何使用它,使用它能达到什么效果 在写本文章时,我也借鉴了网上的部分资源,因为是之前很早搜索到的资料无法追踪源头,所以在此不再写来源,谨感谢各位大神。 1 使用线程池的原因 通常使用多线程都是在需要的时候创建一个新的线程,然后执行任务,完成后退出。一般情况下是完全够满足我们的程序的。 但是当我们需要创建大量的线程,并且执行一个简单的任务之后销毁,比如:在web,email,db里面的一些应用,如彩铃,或者网络通信编程,或者云计算里面后台镜像处理的时候,我们的应用在任何时候都要准备面对数目巨大的连接请求,同时,这些请求执行的任务却又比较简单,占用的时间很少,这样我们可能就会处于不停的创建线程并销毁线程的状态。虽说比起进程的创建,线程的创建时间已经大大缩短,但是如果需要频繁的创建线程,并且每个线程所占用的处理时间又非常简短,则线程创建和销毁带给处理器的额外负担也是很可观的。 线程池的作用正是在这种情况下有效的降低频繁创建销毁线程所带来的额外开销。一般来说,线程池都是采用预创建的技术,在应用启动之初便预先创建一定数目的线程。应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。如果线程池中预先分配的线程已经全部分配完毕,但此时又有新的任务请求,则线程池会动态的创建新的线程去适应这个请求。当然,有可能,某些时段应用并不需要执行很多的任务,导致了线程池中的线程大多处于空闲的状态,为了节省系统资源,线程池就需要动态的销毁其中的一部分空闲线程。因此,线程池都需要一个管理者,按照一定的要求去动态的维护其中线程的数目。 当然,如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了。 2 如何使用它 线程池会维护一个任务链表(每个CThread_worker结构就是一个任务)。 pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine ()函数。该函数中 while (pool->cur_queue_size == 0) { pthread_cond_wait (&(pool->queue_ready),&(pool->queue_lock)); } 表示如果任务链表中没有任务,则该线程出于阻塞等待状态。否则从队列中取出任务并执行。 pool_add_worker()函数向线程池的任务链表中加入一个任务,加入后通过调用pthread_cond_signal (&(pool->queue_ready))唤醒一个出于阻塞状态的线程(如果有的话)。 pool_destroy ()函数用于销毁线程池,线程池任务链表中的任务不会再被执行,但是正在运行的线程会一直把任务运行完后再退出 3 使用它能达到的效果 实际上,创建太多的线程可能会导致由于过度使用系统资源而耗尽内存。为了防止资源不足,服务器应用程序可以采用线程池来限制同一时刻处理的线程数目。线程池不会占用主线程,也不会延迟后续请求的处理。一旦池中的某个线程完成任务,它将返回到等待线程队列中,等待被再次使用。这种重用使应用程序可以避免为每个任务创建新线程引起的资源和时间消耗。 4 代码实现 这是个比较简单的版本,如果想更好的话,需要再改进一年,推荐大家去网上找一下tinyftp的源码,里面有个thread pool的实现很完善很好。 [cpp] view plaincopyprint? <pre name="code" class="cpp">/*********************************************/ // // DATE: 2012-8-3 // TIME: 下午2:42:21 // author: sky // file: simple_pool.c // todo: TODO // /**********************************************/ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #include <assert.h> /* *线程池里所有运行和等待的任务都是一个Thread_worker *由于所有任务都在链表里,所以是一个链表结构 */ typedef struct worker { /*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/ void *(*process_interface)(void * arg); void *arg; struct worker * next; } Thread_worker; typedef struct { pthread_mutex_t pool_mutex; pthread_cond_t pool_cond; /*任务队列的头指针*/ Thread_worker *worker_queue_head; /*是否销毁线程池*/ int is_destory; pthread_t * thread_id; int thread_max_num; int cur_queue_size; } Thread_pool; //此处声明了一个pool的全局变量 Thread_pool *pool = NULL; ////////////////////////////////// // //function:pool_init //arguments:thread_max_num //TODO:初始化连接池 // /////////////////////////////////// void pool_init(int thread_max_num); ////////////////////////////////// // //function:pool_add_worker //arguments:void *(*process)(void *args), void *args //TODO:添加任务 // /////////////////////////////////// int pool_add_worker(void *(*process)(void *args), void *args); void *thread_routine(void * args); ////////////////////////////////// // //function:pool_destory //arguments: //TODO:销毁连接池 // /////////////////////////////////// int pool_destory(); ////////////////////// //具体实现如下 /////////////////////// void pool_init(int thread_max_num) { pool = (Thread_pool *) malloc(sizeof(Thread_pool)); pthread_mutex_init(&(pool->pool_mutex), NULL ); pthread_cond_init(&(pool->pool_cond), NULL ); pool->is_destory = 0; //0代表不销毁 pool->worker_queue_head = NULL; pool->thread_max_num = thread_max_num; pool->cur_queue_size = 0; pool->thread_id = (pthread_t *) malloc(sizeof(pthread_t) * thread_max_num); int i = 0; for (; i < thread_max_num; i++) { pthread_create(&(pool->thread_id[i]), NULL, thread_routine, NULL ); } } void * thread_routine(void *args) { printf("starting thread 0x%x\n", pthread_self()); while (1) { /*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意 pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/ pthread_mutex_lock(&(pool->pool_mutex)); while (pool->cur_queue_size == 0 && !pool->is_destory) { printf("thread 0x%x is waiting\n", pthread_self()); pthread_cond_wait(&(pool->pool_cond), &(pool->pool_mutex)); } /*线程池要销毁了*/ if (pool->is_destory) { pthread_mutex_unlock(&(pool->pool_mutex)); printf("thread 0x%x will exit\n", pthread_self()); pthread_exit(NULL ); } printf("thread 0x%x is starting to work\n", pthread_self()); assert(pool->cur_queue_size!=0); assert(pool->worker_queue_head!=NULL); pool->cur_queue_size--; Thread_worker *worker = pool->worker_queue_head; pool->worker_queue_head = worker->next; pthread_mutex_unlock(&(pool->pool_mutex)); /*调用回调函数,执行任务*/ (*(worker->process_interface))(worker->arg); free(worker); worker = NULL; } pthread_exit(NULL ); } int pool_add_worker(void *(*process)(void * args), void*args) { Thread_worker *new_worker = (Thread_worker *) malloc(sizeof(Thread_worker)); new_worker->process_interface = process; new_worker->arg = args; new_worker->next = NULL; /*将任务加入到等待队列中*/ pthread_mutex_lock(&(pool->pool_mutex)); Thread_worker *member = pool->worker_queue_head; if (member != NULL ) { while (member->next != NULL ) member = member->next; member->next = new_worker; } else { pool->worker_queue_head = new_worker; } assert(pool->worker_queue_head!=NULL); pool->cur_queue_size++; pthread_mutex_unlock(&(pool->pool_mutex)); /*好了,等待队列中有任务了,唤醒一个等待线程;*/ pthread_cond_signal(&(pool->pool_cond)); return 0; } int pool_destory() { if (pool->is_destory) return -1; pool->is_destory = 1; /*唤醒所有等待线程,线程池要销毁了*/ pthread_cond_broadcast(&(pool->pool_cond)); int i; for (i = 0; i < pool->thread_max_num; i++) pthread_join(pool->thread_id[i], NULL ); /*销毁各种变量*/ free(pool->thread_id); Thread_worker *temp = NULL; while (pool->worker_queue_head != NULL ) { temp = pool->worker_queue_head; pool->worker_queue_head = pool->worker_queue_head->next; free(temp); } pthread_mutex_destroy(&(pool->pool_mutex)); pthread_cond_destroy(&(pool->pool_cond)); free(pool); pool = NULL; return 0; } /////////////////////////////////////// //下面的代码就是如何调用thread pool /////////////////////////////////////// void * my_process(void *arg) { printf("Thread_id is 0x%x , working on task %d\n", pthread_self(), *(int *) arg); sleep(1); return NULL ; } int main(int argc, char *argv[]) { pool_init(3); int *working_num = (int *) malloc(sizeof(int) * 5); int i = 0; for (; i < 5; i++) { working_num[i] = i; pool_add_worker(my_process, &working_num[i]); } sleep(5); pool_destory(); free(working_num); return 0; } </pre><br><br> 5 运行测试 $ gcc -o threadpool threadpool.c -lpthread
mmzhzjia 2013-08-21
  • 打赏
  • 举报
回复
复制粘贴别人的 c语言中没有线程池,但是项目要用到,于是就从网上找了个代码,根据我的情况改了改,大体可以用了。 大概的过程是这样的。 1)初始化线程池,指定最大线程数; 2)将工作线程添加到线程池的等待队列中; 3)创建线程; 4)依次执行线程,等待队列中没有线程的话,线程就会彻底退出了; 5)等待所有线程结束; 6)销毁线程,退出。
mmzhzjia 2013-08-21
  • 打赏
  • 举报
回复
引用 5 楼 zhao4zhong1 的回复:
领导有一项任务,还有几个手下: 一:领导开会通知不忙的手下,哪个手下抢到就由哪个手下完成。 二:领导挑一个不忙的手下出来,然后把任务给他。
亲 跟线程池对应一下该怎么说呢
赵4老师 2013-08-21
  • 打赏
  • 举报
回复
领导有一项任务,还有几个手下: 一:领导开会通知不忙的手下,哪个手下抢到就由哪个手下完成。 二:领导挑一个不忙的手下出来,然后把任务给他。
mmzhzjia 2013-08-21
  • 打赏
  • 举报
回复
别人写的 自己收藏 慢慢研究 C语言实现简单线程池 有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池。下面是一个C语言实现的简单的线程池。 头文件: 1: #ifndef THREAD_POOL_H__ 2: #define THREAD_POOL_H__ 3: 4: #include <pthread.h> 5: 6: /* 要执行的任务链表 */ 7: typedef struct tpool_work { 8: void* (*routine)(void*); /* 任务函数 */ 9: void *arg; /* 传入任务函数的参数 */ 10: struct tpool_work *next; 11: }tpool_work_t; 12: 13: typedef struct tpool { 14: int shutdown; /* 线程池是否销毁 */ 15: int max_thr_num; /* 最大线程数 */ 16: pthread_t *thr_id; /* 线程ID数组 */ 17: tpool_work_t *queue_head; /* 线程链表 */ 18: pthread_mutex_t queue_lock; 19: pthread_cond_t queue_ready; 20: }tpool_t; 21: 22: /* 23: * @brief 创建线程池 24: * @param max_thr_num 最大线程数 25: * @return 0: 成功 其他: 失败 26: */ 27: int 28: tpool_create(int max_thr_num); 29: 30: /* 31: * @brief 销毁线程池 32: */ 33: void 34: tpool_destroy(); 35: 36: /* 37: * @brief 向线程池中添加任务 38: * @param routine 任务函数指针 39: * @param arg 任务函数参数 40: * @return 0: 成功 其他:失败 41: */ 42: int 43: tpool_add_work(void*(*routine)(void*), void *arg); 44: 45: #endif 实现: 1: #include <unistd.h> 2: #include <stdlib.h> 3: #include <errno.h> 4: #include <string.h> 5: #include <stdio.h> 6: 7: #include "tpool.h" 8: 9: static tpool_t *tpool = NULL; 10: 11: /* 工作者线程函数, 从任务链表中取出任务并执行 */ 12: static void* 13: thread_routine(void *arg) 14: { 15: tpool_work_t *work; 16: 17: while(1) { 18: /* 如果线程池没有被销毁且没有任务要执行,则等待 */ 19: pthread_mutex_lock(&tpool->queue_lock); 20: while(!tpool->queue_head && !tpool->shutdown) { 21: pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock); 22: } 23: if (tpool->shutdown) { 24: pthread_mutex_unlock(&tpool->queue_lock); 25: pthread_exit(NULL); 26: } 27: work = tpool->queue_head; 28: tpool->queue_head = tpool->queue_head->next; 29: pthread_mutex_unlock(&tpool->queue_lock); 30: 31: work->routine(work->arg); 32: free(work); 33: } 34: 35: return NULL; 36: } 37: 38: /* 39: * 创建线程池 40: */ 41: int 42: tpool_create(int max_thr_num) 43: { 44: int i; 45: 46: tpool = calloc(1, sizeof(tpool_t)); 47: if (!tpool) { 48: printf("%s: calloc failed\n", __FUNCTION__); 49: exit(1); 50: } 51: 52: /* 初始化 */ 53: tpool->max_thr_num = max_thr_num; 54: tpool->shutdown = 0; 55: tpool->queue_head = NULL; 56: if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) { 57: printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n", 58: __FUNCTION__, errno, strerror(errno)); 59: exit(1); 60: } 61: if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) { 62: printf("%s: pthread_cond_init failed, errno:%d, error:%s\n", 63: __FUNCTION__, errno, strerror(errno)); 64: exit(1); 65: } 66: 67: /* 创建工作者线程 */ 68: tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t)); 69: if (!tpool->thr_id) { 70: printf("%s: calloc failed\n", __FUNCTION__); 71: exit(1); 72: } 73: for (i = 0; i < max_thr_num; ++i) { 74: if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){ 75: printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__, 76: errno, strerror(errno)); 77: exit(1); 78: } 79: 80: } 81: 82: return 0; 83: } 84: 85: /* 销毁线程池 */ 86: void 87: tpool_destroy() 88: { 89: int i; 90: tpool_work_t *member; 91: 92: if (tpool->shutdown) { 93: return; 94: } 95: tpool->shutdown = 1; 96: 97: /* 通知所有正在等待的线程 */ 98: pthread_mutex_lock(&tpool->queue_lock); 99: pthread_cond_broadcast(&tpool->queue_ready); 100: pthread_mutex_unlock(&tpool->queue_lock); 101: for (i = 0; i < tpool->max_thr_num; ++i) { 102: pthread_join(tpool->thr_id[i], NULL); 103: } 104: free(tpool->thr_id); 105: 106: while(tpool->queue_head) { 107: member = tpool->queue_head; 108: tpool->queue_head = tpool->queue_head->next; 109: free(member); 110: } 111: 112: pthread_mutex_destroy(&tpool->queue_lock); 113: pthread_cond_destroy(&tpool->queue_ready); 114: 115: free(tpool); 116: } 117: 118: /* 向线程池添加任务 */ 119: int 120: tpool_add_work(void*(*routine)(void*), void *arg) 121: { 122: tpool_work_t *work, *member; 123: 124: if (!routine){ 125: printf("%s:Invalid argument\n", __FUNCTION__); 126: return -1; 127: } 128: 129: work = malloc(sizeof(tpool_work_t)); 130: if (!work) { 131: printf("%s:malloc failed\n", __FUNCTION__); 132: return -1; 133: } 134: work->routine = routine; 135: work->arg = arg; 136: work->next = NULL; 137: 138: pthread_mutex_lock(&tpool->queue_lock); 139: member = tpool->queue_head; 140: if (!member) { 141: tpool->queue_head = work; 142: } else { 143: while(member->next) { 144: member = member->next; 145: } 146: member->next = work; 147: } 148: /* 通知工作者线程,有新任务添加 */ 149: pthread_cond_signal(&tpool->queue_ready); 150: pthread_mutex_unlock(&tpool->queue_lock); 151: 152: return 0; 153: } 154: 155: 测试代码: 1: #include <unistd.h> 2: #include <stdio.h> 3: #include <stdlib.h> 4: #include "tpool.h" 5: 6: void *func(void *arg) 7: { 8: printf("thread %d\n", (int)arg); 9: return NULL; 10: } 11: 12: int 13: main(int arg, char **argv) 14: { 15: if (tpool_create(5) != 0) { 16: printf("tpool_create failed\n"); 17: exit(1); 18: } 19: 20: int i; 21: for (i = 0; i < 10; ++i) { 22: tpool_add_work(func, (void*)i); 23: } 24: sleep(2); 25: tpool_destroy(); 26: return 0; 27: } 这个实现是在调用tpool_destroy之后,仅将当前正在执行的任务完成之后就会退出,我们也可以修改代码使得线程池在执行完任务链表中所有任务后再退出。
max_min_ 2013-08-21
  • 打赏
  • 举报
回复
对于单核的cpu来说, 创建N个线程的话, 就是一个共用电话分N个人用,所有人谁先抢到,谁就能用! 其他人都阻塞等待这个人用完, 用完后其他人才重新竞争谁来用!,当然来竞争的要求是要有钱(线程的其他准备资源) 对于多核的cpu来说,创建N个线程的话, 就相当于多个个共用电话了(几个由cpu来决定的),同时有多个人在用电话了, 其他人就等待了,等有人用完,在抢占电话来用 整个轮询了!
大尾巴猫 2013-08-21
  • 打赏
  • 举报
回复
第一个。线程是抢的。
modyaj 2013-08-21
  • 打赏
  • 举报
回复

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧