下面的程序就是完整的線程池實現,主要採用互斥量和條件變量實現同步
首先定義頭文件threadpool.h
在該文件中定義了線程池的數據結構和所有的函數
#ifndef THREADPOOL_H_
#define THREADPOOL_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
/**
* 線程體數據結構
*/
typedef struct runner
{
void (*callback)(void* arg); // 回調函數指針
void* arg; // 回調函數的參數
struct runner* next;
} thread_runner;
/**
* 線程池數據結構
*/
typedef struct
{
pthread_mutex_t mutex; //互斥量
pthread_cond_t cond; // 條件變量
thread_runner* runner_head; // 線程池中所有等待任務的頭指針
thread_runner* runner_tail; // 線程池所有等待任務的尾指針
int shutdown; // 線程池是否銷燬
pthread_t* threads; // 所有線程
int max_thread_size; //線程池中允許的活動線程數目
} thread_pool;
/**
* 線程體
*/
void run(void *arg);
/**
* 初始化線程池
* 參數:
* pool:指向線程池結構有效地址的動態指針
* max_thread_size:最大的線程數
*/
void threadpool_init(thread_pool* pool, int max_thread_size);
/**
* 向線程池加入任務
* 參數:
* pool:指向線程池結構有效地址的動態指針
* callback:線程回調函數
* arg:回調函數參數
*/
void threadpool_add_runner(thread_pool* pool, void (*callback)(void *arg), void *arg);
/**
* 銷燬線程池
* 參數:
* ppool:指向線程池結構有效地址的動態指針地址(二級指針),銷燬後釋放內存,該指針爲NULL
*/
void threadpool_destroy(thread_pool** ppool);
#endif
然後是函數實現threadpool.h
該文件實現了threadpool.h的函數定義
#include "threadpool.h"
#define DEBUG 1
/**
* 線程體
*/
void run(void *arg)
{
thread_pool* pool = (thread_pool*) arg;
while (1)
{
// 加鎖
pthread_mutex_lock(&(pool->mutex));
#ifdef DEBUG
printf("run-> locked\n");
#endif
// 如果等待隊列爲0並且線程池未銷燬,則處於阻塞狀態
while (pool->runner_head == NULL && !pool->shutdown)
{
pthread_cond_wait(&(pool->cond), &(pool->mutex));
}
//如果線程池已經銷燬
if (pool->shutdown)
{
// 解鎖
pthread_mutex_unlock(&(pool->mutex));
#ifdef DEBUG
printf("run-> unlocked and thread exit\n");
#endif
pthread_exit(NULL);
}
// 取出鏈表中的頭元素
thread_runner *runner = pool->runner_head;
pool->runner_head = runner->next;
// 解鎖
pthread_mutex_unlock(&(pool->mutex));
#ifdef DEBUG
printf("run-> unlocked\n");
#endif
// 調用回調函數,執行任務
(runner->callback)(runner->arg);
free(runner);
runner = NULL;
#ifdef DEBUG
printf("run-> runned and free runner\n");
#endif
}
pthread_exit(NULL);
}
/**
* 初始化線程池
* 參數:
* pool:指向線程池結構有效地址的動態指針
* max_thread_size:最大的線程數
*/
void threadpool_init(thread_pool* pool, int max_thread_size)
{
// 初始化互斥量
pthread_mutex_init(&(pool->mutex), NULL);
// 初始化條件變量
pthread_cond_init(&(pool->cond), NULL);
pool->runner_head = NULL;
pool->runner_tail = NULL;
pool->max_thread_size = max_thread_size;
pool->shutdown = 0;
// 創建所有分離態線程
pool->threads = (pthread_t *) malloc(max_thread_size * sizeof(pthread_t));
int i = 0;
for (i = 0; i < max_thread_size; i++)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&(pool->threads[i]), &attr, (void*) run, (void*) pool);
}
#ifdef DEBUG
printf("threadpool_init-> create %d detached thread\n", max_thread_size);
#endif
}
/**
* 向線程池加入任務
* 參數:
* pool:指向線程池結構有效地址的動態指針
* callback:線程回調函數
* arg:回調函數參數
*/
void threadpool_add_runner(thread_pool* pool, void (*callback)(void *arg), void *arg)
{
// 構造一個新任務
thread_runner *newrunner = (thread_runner *) malloc(sizeof(thread_runner));
newrunner->callback = callback;
newrunner->arg = arg;
newrunner->next = NULL;
// 加鎖
pthread_mutex_lock(&(pool->mutex));
#ifdef DEBUG
printf("threadpool_add_runner-> locked\n");
#endif
// 將任務加入到等待隊列中
if (pool->runner_head != NULL)
{
pool->runner_tail->next = newrunner;
pool->runner_tail = newrunner;
}
else
{
pool->runner_head = newrunner;
pool->runner_tail = newrunner;
}
// 解鎖
pthread_mutex_unlock(&(pool->mutex));
#ifdef DEBUG
printf("threadpool_add_runner-> unlocked\n");
#endif
// 喚醒一個等待線程
pthread_cond_signal(&(pool->cond));
#ifdef DEBUG
printf("threadpool_add_runner-> add a runner and wakeup a waiting thread\n");
#endif
}
/**
* 銷燬線程池
* 參數:
* ppool:指向線程池結構有效地址的動態指針地址(二級指針)
*/
void threadpool_destroy(thread_pool** ppool)
{
thread_pool *pool = *ppool;
// 防止2次銷燬
if (!pool->shutdown)
{
pool->shutdown = 1;
// 喚醒所有等待線程,線程池要銷燬了
pthread_cond_broadcast(&(pool->cond));
// 等待所有線程中止
sleep(1);
#ifdef DEBUG
printf("threadpool_destroy-> wakeup all waiting threads\n");
#endif
// 回收空間
free(pool->threads);
// 銷燬等待隊列
thread_runner *head = NULL;
while (pool->runner_head != NULL)
{
head = pool->runner_head;
pool->runner_head = pool->runner_head->next;
free(head);
}
#ifdef DEBUG
printf("threadpool_destroy-> all runners freed\n");
#endif
/*條件變量和互斥量也別忘了銷燬*/
pthread_mutex_destroy(&(pool->mutex));
pthread_cond_destroy(&(pool->cond));
#ifdef DEBUG
printf("threadpool_destroy-> mutex and cond destoryed\n");
#endif
free(pool);
(*ppool) = NULL;
#ifdef DEBUG
printf("threadpool_destroy-> pool freed\n");
#endif
}
}
以上就是完整的線城池實現
下面寫個測試程序來看看
#include "threadpool.h"
void threadrun(void* arg)
{
int *i = (int *) arg;
printf("%d\n", *i);
}
int main(void)
{
thread_pool *pool = malloc(sizeof(thread_pool));
threadpool_init(pool, 2);
int i;
int tmp[3];
for (i = 0; i < 3; i++)
{
tmp[i] = i;
threadpool_add_runner(pool, threadrun, &tmp[i]);
}
sleep(1);
threadpool_destroy(&pool);
printf("main-> %p\n",pool);
printf("main-> test over\n");
return 0;
}
該函數創建了1個線程池,包含2個線程,然後往線程池中加入了3個任務
並在最後打印了線程池的指針地址(主要是爲了看線程池銷燬後的狀態)
運行結果如下:
輸出的信息主要調試信息,
值得注意的是倒數第二行“main-> (nil)”
說明線程池銷燬後,指向線程池的指針 = NULL(這就是爲什麼在threadpool_destory函數爲什麼要用二級指針的原因)
轉載地址:http://blog.163.com/sean_zwx/blog/static/169032755201232461650707/