一:线程池头文件
#include
#include
typedef void *(*function_t)(void *arg);
/* jobs */
typedef struct thread_job_t{
function_t pf;
void *arg;
struct thread_job_t *next;
struct thread_job_t *prev;
}thread_job_t;
/* thread pool */
typedef struct thread_pool_t{
pthread_t *threads;
int num_threads;
thread_job_t *head;
thread_job_t *tail;
int num_jobs;
sem_t *queue_sem;
}thread_pool_t;
/*
*@brief: initialize thread pool
*Allocates memory for the thread pool, workqueue, semaphore and fixes
*pointer in job queue
*@param num_threads to be used
*@return pointer to thread_pool_t struct on success
* NULL on error
*/
thread_pool_t *thread_pool_init(int num_threads);
/*
*@brief: destory thread pool
*if there are so many jobs and can't handle all of them ,free the job_queue
*if there are so many threads, wake all of them in case of zoombie
*@param thread pool
*/
void thread_pool_destory(thread_pool_t *thread_pool);
/*
*@brief: do the jobs, all of the threads are blocked when they first created
*@param thread_pool_in
*/
void thread_pool_thread_do(thread_pool_t *thread_pool_in);
/*
*@brief: add the job into the job_queue, it will wake the blocked threads by sem_post
*@param thread pool
*@param pointer to the job function
*@param argument's of function
*@return 0 on success, other on failure
*/
int thread_pool_add_work(thread_pool_t *thread_pool, function_t pf, void *arg);
/*
*@brief:add job into the queue
*@param thread pool
*@param pointer to the struct of thread_job_t
*@return 0 on success, other on failure
*/
int thread_pool_job_enqueue(thread_pool_t *thread_pool, thread_job_t *job);
/*
*@brief:remove the first data unit of queue
*@param thread pool
*@return 0 on success, other on failure
*/
thread_job_t *thread_pool_job_delqueue(thread_pool_t *thread_pool);
/*
*@brief:make the job queue empty
*@param thread pool
*@return 0 on success, other on failure
*/
int thread_pool_job_queue_empty(thread_pool_t *thread_pool);
二:线程池函数实现
#include "thread_pool_test.h"
#include
#include
#include
#include
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef int bool;
#define true 1
#define false 0
bool thread_is_live = true;
#define CHECK_ERROR(a) \
if((a)) \
{ \
perror("Error ad line\n\t" #a "\nSystem Msg");\
exit(EXIT_FAILURE); \
}
thread_pool_t *thread_pool_init(int num_threads)
{
if (1 > num_threads)
num_threads = 1;
thread_pool_t *thread_pool = (thread_pool_t *)malloc(sizeof(thread_pool_t));
thread_pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * num_threads);
thread_pool->num_threads = num_threads;
thread_pool->head = NULL;
thread_pool->tail = NULL;
thread_pool->num_jobs = 0;
thread_pool->queue_sem = (sem_t *)malloc(sizeof(sem_t));
sem_init(thread_pool->queue_sem, 0, 0);
int i;
for(i = 0; i < num_threads; i++)
{
pthread_create(&thread_pool->threads[i], NULL, (void *)thread_pool_thread_do, (void *)thread_pool);
}
return thread_pool;
}
void thread_pool_destory(thread_pool_t *thread_pool)
{
thread_is_live = false;
int i;
for(i = 0; i < thread_pool->num_threads; i++)
{
CHECK_ERROR(sem_post(thread_pool->queue_sem));
}
CHECK_ERROR(sem_destroy(thread_pool->queue_sem));
for (i = 0; i < thread_pool->threads[i]; i++)
{
pthread_join(thread_pool->threads[i], NULL);
}
thread_pool_job_queue_empty(thread_pool);
free(thread_pool->threads);
free(thread_pool->queue_sem);
free(thread_pool);
}
int thread_pool_job_queue_empty(thread_pool_t *thread_pool)
{
thread_job_t *prev = thread_pool->head;
thread_job_t *p = prev;
while(thread_pool->num_jobs)
{
p = p->next;
free(prev);
prev = p;
thread_pool->num_jobs--;
}
thread_pool->head = NULL;
thread_pool->tail = NULL;
return 0;
}
void thread_pool_thread_do(thread_pool_t *thread_pool_in)
{
assert(thread_pool_in);
thread_pool_t *thread_pool = thread_pool_in;
if (sem_wait(thread_pool->queue_sem))
{
perror("thread waiting for semaphore");
exit(EXIT_FAILURE);
}
while(thread_is_live)
{
pthread_mutex_lock(&mutex);
thread_job_t *job = thread_pool_job_delqueue(thread_pool);
pthread_mutex_unlock(&mutex);
if (job)
{
function_t pf = job->pf;
void *arg = job->arg;
pf(arg);
free(job);
}
}
}
thread_job_t *thread_pool_job_delqueue(thread_pool_t *thread_pool)
{
assert(thread_pool);
thread_job_t *job = thread_pool->head;
switch(thread_pool->num_jobs){
case 0:
job = NULL;
break;
case 1:
thread_pool->head = NULL;
thread_pool->tail = NULL;
thread_pool->num_jobs--;
break;
default:
thread_pool->head = job->next;
job->next = NULL;
thread_pool->head->prev = NULL;
thread_pool->num_jobs--;
break;
}
return job;
}
int thread_pool_add_work(thread_pool_t *thread_pool, function_t pf, void *arg)
{
assert(thread_pool);
thread_job_t *job = (thread_job_t *)malloc(sizeof(thread_job_t));
job->pf = pf;
job->arg = arg;
job->next = NULL;
job->prev = NULL;
pthread_mutex_lock(&mutex);
CHECK_ERROR(thread_pool_job_enqueue(thread_pool, job));
pthread_mutex_unlock(&mutex);
return 0;
}
int thread_pool_job_enqueue(thread_pool_t *thread_pool, thread_job_t *job)
{
assert(thread_pool);
assert(job);
switch(thread_pool->num_jobs){
case 0:
thread_pool->head = job;
thread_pool->tail = job;
thread_pool->num_jobs++;
break;
default:
thread_pool->tail->next = job;
job->prev = thread_pool->tail;
thread_pool->tail = job;
thread_pool->num_jobs++;
}
sem_post(thread_pool->queue_sem);
return 0;
}
三:测试代码
#include "thread_pool_test.h"
#include
#include
void task1()
{
printf("Thread %d running task1!\n", (int)pthread_self());
int i, sum = 0;
for (i = 0; i < 100000; i++)
{
sum += i;
}
}
void task2(int id)
{
printf("%d Thread %d running task2!\n", id, (int)pthread_self());
int i, sum = 0;
for (i = 0; i < 100000; i++)
{
sum += i;
}
}
int main(int argc, const char *argv[])
{
thread_pool_t *thread_pool = thread_pool_init(10);
int i;
for (i = 0; i < 1000; i++)
{
thread_pool_add_work(thread_pool, (void *)task1, NULL);
thread_pool_add_work(thread_pool, (void *)task2, (void *)i);
}
sleep(5);
thread_pool_destory(thread_pool);
return 0;
}