之前的代码,在执行完任务后,没有对任务进行释放,是有将任务队列改成任务资源回收重复利用以减少内存频繁分配释放的想法,这里还是先加上了,作为半成品用着先。
pool.h
#ifndef _TASK_QUEUE_
#define _TASK_QUEUE_
#include <pthread.h>
//#include <stdarg.h>
#ifdef __cpluscplus_
extern "C"{
#endif
struct pool_tasks{
//task interface
void (*excute)(void* param);
//task param
void* param;
//task queue link
struct pool_tasks* next;
};
struct pool_ctx{
//numbers of thead
int worker_size;
//max size of threads pool
int max_worker_size;//
//size indicate the task numbers in the queue
int queue_size;
//a flag to control the workers exit or not,set to 1 means exit,0 means continue running
int exit;
//dynamic space to store all worker threads id
pthread_t *threads_id;
pthread_mutex_t queue_mutex;
pthread_cond_t worker_cond;
//
struct pool_tasks* header;
struct pool_tasks* tailer;
};
struct pool_ctx* thread_pool_init(int);
int thread_pool_add(struct pool_ctx*,void*,void (*)(void*));
int thread_pool_close(struct pool_ctx*);
#ifdef __cplusplus
}
#endif
#endif
pool.c
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "thread_pool.h"
void pthread_main(void* arg){
struct pool_ctx* pool = (struct pool_ctx*)arg;
while(1/*!pool->exit*/){
struct pool_tasks* exce_task = NULL;
pthread_mutex_lock(&pool->queue_mutex);
if(pool->queue_size == 0 && pool->exit){//exit
pthread_mutex_unlock(&pool->queue_mutex);
break;
}
if(pool->queue_size == 0){//sleep
pthread_cond_wait(&pool->worker_cond,&pool->queue_mutex);
pthread_mutex_unlock(&pool->queue_mutex);
}
else{//there are tasks in the queue
//get the head task from queue
exce_task = pool->header;
//move next task up to the head of the queue
pool->header = pool->header->next;
if(0 == --pool->queue_size)
pool->tailer = NULL;
pthread_mutex_unlock(&pool->queue_mutex);
//excute task...
exce_task->excute(exce_task->param);
//free task?
//no,we don't free the data here instead of letting the client to free it
//by himself in the business
free(exce_task);//20140928
exce_task = NULL;//20140928
}
}
}
struct pool_ctx* thread_pool_init(int size){
//allocate memory for pool
struct pool_ctx* pool = (struct pool_ctx*)malloc(/*size **/sizeof(struct pool_ctx));
//malloc failed
if(NULL == pool){
printf("create thread pool error.errno=%d,%s\n",errno,strerror(errno));
return NULL;
}
//initialize mutex
if(0 != pthread_mutex_init(&pool->queue_mutex,NULL)){
printf("pthread_mutex_init queue_mutex error,errno=%d,%s,free pool\n",errno,strerror(errno));
//free the memory allocated before,then return NULL.
free(pool);
return NULL;
}
//initialize cond
if(0 != pthread_cond_init(&pool->worker_cond,NULL)){
printf("pthread_cond_init worker_cond error,errno=%d,%s,free pool\n",errno,strerror);
//destroy mutex initialized beore
pthread_mutex_destroy(&pool->queue_mutex);
//free memory allocated before
free(pool);
//return
return NULL;
}
//allocate sequence memory space for multiple pthread_t id
pool->threads_id = (pthread_t*)malloc(size * sizeof(pthread_t));
if(NULL == pool->threads_id){
printf("malloc multiple pthread_t error,errno=%d,%s\n",errno,strerror(errno));
//destroy mutex initialized beore
pthread_mutex_destroy(&pool->queue_mutex);
//destroy cond initialized before
pthread_cond_destroy(&pool->worker_cond);
//free memory allocated before
free(pool);
//return
return NULL;
}
pool->max_worker_size = size;
pool->worker_size = size;
pool->queue_size = 0;
pool->exit = 0;
pool->header = NULL;
pool->tailer = NULL;
//create worker threads
int idx;
for(idx = 0; idx < size; ++ idx)
pthread_create(&pool->threads_id[idx],NULL,(void*(*)(void*))pthread_main,pool);
return pool;
}
int thread_pool_add(struct pool_ctx* pool,void* param,void (*call_back)(void* param)){
if(NULL == pool){
printf("thread pool is null..add return.\n");
return -1;
}
if(NULL == call_back){
printf("task function is NULL,no task added.\n");
return -1;
}
struct pool_tasks* new_task = malloc(sizeof(struct pool_tasks));
if(NULL == new_task){
printf("create new task error,errno=%d,%s\n",errno,strerror(errno));
return -1;
}
new_task->param = param;
new_task->excute = call_back;
new_task->next = NULL;
pthread_mutex_lock(&pool->queue_mutex);
if(0 == pool->queue_size){
pool->header = new_task;
pool->tailer = new_task;
}
else{
pool->tailer->next = new_task;
pool->tailer = new_task;
}
++pool->queue_size;
pthread_cond_signal(&pool->worker_cond);
pthread_mutex_unlock(&pool->queue_mutex);
}
int thread_pool_close(struct pool_ctx* pool){
if(NULL == pool)
return 0;
//set the global flag to exit,and broadcast the signal
pthread_mutex_lock(&pool->queue_mutex);
pool->exit = 1;
//release the queue
/*while(pool->queue_size > 0){
pool_tasks* tmp = pool->header;
pool->header = pool->header->next;
--pool->queue_size;
free(tmp);
}*/
pthread_cond_broadcast(&pool->worker_cond);
pthread_mutex_unlock(&pool->queue_mutex);
//join all worker threads
int idx;
for(idx = 0; idx < pool->worker_size; ++ idx)
pthread_join(pool->threads_id[idx],NULL);
//release threads resource
free(pool->threads_id);
pool->threads_id = NULL;
//release mutex and cond
pthread_cond_destroy(&pool->worker_cond);
pthread_mutex_destroy(&pool->queue_mutex);
free(pool);
pool = NULL;
return 0;
}
test.c
#include <stdio.h>
#include "thread_pool.h"
void mycb(void* arg);
int main(int argc,char** argv){
struct pool_ctx* pool = thread_pool_init(5);
int i;
for(i =0;i < 1000; ++i)
thread_pool_add(pool,(void*)i,(void (*)(void*))mycb);
thread_pool_close(pool);
return 0;
}
void mycb(void* arg){
int i = (int)arg;
printf("%d\n",i);
}
gcc -g -c thread_pool.c -lthread -o threadpool.o
gcc -lpthread thread_pool_test.c threadpool.o