=================== thread_pool.h ===============================
#ifndef THREAD_POOL_H__
#define THREAD_POOL_H__
#include <pthread.h>
/* 要執行的任務鏈表 */
typedef struct tpool_work {
void* (*routine)(void*); /* 任務函數 */
void *arg; /* 傳入任務函數的參數 */
struct tpool_work *next;
}tpool_work_t;
typedef struct tpool {
int shutdown; /* 線程池是否銷燬 */
int max_thr_num; /* 最大線程數 */
pthread_t *thr_id; /* 線程ID數組 */
tpool_work_t *queue_head; /* 線程鏈表 */
pthread_mutex_t queue_lock;
pthread_cond_t queue_ready;
}tpool_t;
/*
* @brief 創建線程池
* @param max_thr_num 最大線程數
* @return 0: 成功 其他: 失敗
*/
int
tpool_create(int max_thr_num);
/*
* @brief 銷燬線程池
*/
void
tpool_destroy();
/*
@brief 向線程池中添加任務
@param routine 任務函數指針
@param arg 任務函數參數
@return 0: 成功 其他:失敗
*/
int
tpool_add_work(void*(*routine)(void*), void *arg);
#endif
----------------------------------------------------------------------thread_pool.h-----------------------------------------
========================thread_pool.c ==================================
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "thread_pool.h"
static tpool_t *tpool = NULL;
/* 工作者線程函數, 從任務鏈表中取出任務並執行 */
static void*
thread_routine(void *arg)
{
tpool_work_t *work;
while(1) {
/* 如果線程池沒有被銷燬且沒有任務要執行,則等待 */
pthread_mutex_lock(&tpool->queue_lock);
while(!tpool->queue_head && !tpool->shutdown) {///線程池沒有被銷燬,且沒有任務要執行
pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock);
}
if (tpool->shutdown) {///線程池被銷燬
pthread_mutex_unlock(&tpool->queue_lock);
pthread_exit(NULL);
}
work = tpool->queue_head;
tpool->queue_head = tpool->queue_head->next;///獲得任務後線程池偏移。
pthread_mutex_unlock(&tpool->queue_lock);
work->routine(work->arg);
free(work);
}
return NULL;
}
/*
* 創建線程池
*/
int
tpool_create(int max_thr_num)
{
int i;
tpool = calloc(1, sizeof(tpool_t));
if (!tpool) {
printf("%s: calloc failed\n", __FUNCTION__);
exit(1);
}
/* 初始化 */
tpool->max_thr_num = max_thr_num;
tpool->shutdown = 0;///0代表未被銷燬
tpool->queue_head = NULL;
if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) {///初始化互斥量
printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n",
__FUNCTION__, errno, strerror(errno));
exit(1);
}
if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) {///初始化條件變量
printf("%s: pthread_cond_init failed, errno:%d, error:%s\n",
__FUNCTION__, errno, strerror(errno));
exit(1);
}
/* 創建工作者線程 */
tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t));
if (!tpool->thr_id) {
printf("%s: calloc failed\n", __FUNCTION__);
exit(1);
}
///創建線程池
for (i = 0; i < max_thr_num; ++i) {
if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){
printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__,
errno, strerror(errno));
exit(1);
}
/*
優先級 []大於->大於&
第一個參數爲指向線程標識符的指針。
第二個參數用來設置線程屬性。
第三個參數是線程運行函數的起始地址。
最後一個參數是運行函數的參數。
*/
}
return 0;
}
/* 銷燬線程池 */
void
tpool_destroy()
{
int i;
tpool_work_t *member;
if (tpool->shutdown) {///線程池已經被銷燬則直接返回。
return;
}
tpool->shutdown = 1;///代表線程池被設置爲銷燬。
/* 通知所有正在等待的線程 */
pthread_mutex_lock(&tpool->queue_lock);
pthread_cond_broadcast(&tpool->queue_ready);///
pthread_mutex_unlock(&tpool->queue_lock);
for (i = 0; i < tpool->max_thr_num; ++i) {
pthread_join(tpool->thr_id[i], NULL);///回收退出的線程
}
free(tpool->thr_id);
while(tpool->queue_head) {
member = tpool->queue_head;
tpool->queue_head = tpool->queue_head->next;
free(member);
}
pthread_mutex_destroy(&tpool->queue_lock);
pthread_cond_destroy(&tpool->queue_ready);
free(tpool);
}
/* 向線程池添加任務 */
int
tpool_add_work(void*(*routine)(void*), void *arg)
{
tpool_work_t *work, *member;
if (!routine){
printf("%s:Invalid argument\n", __FUNCTION__);
return -1;
}
work = malloc(sizeof(tpool_work_t));
if (!work) {
printf("%s:malloc failed\n", __FUNCTION__);
return -1;
}
work->routine = routine;
work->arg = arg;
work->next = NULL;
pthread_mutex_lock(&tpool->queue_lock);
member = tpool->queue_head;
if (!member) {///當前任務隊列爲空,添加的爲第一個任務
tpool->queue_head = work;
} else {///將任務添加到隊列的末尾
while(member->next) {
member = member->next;
}
member->next = work;
}
/* 通知工作者線程,有新任務添加 */
pthread_cond_signal(&tpool->queue_ready);///應該是隨機通知一個等待線程
pthread_mutex_unlock(&tpool->queue_lock);
return 0;
}
--------------------------------------------------thread_pool.c-----------------------------------------
=====================test.c=====================
/*
創建線程池後,線程池while(1)等待任務,tpool_add_work添加任務。
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "thread_pool.h"
void *func(void *arg)
{
printf("thread %d\n", *((int *)arg));
return NULL;
}
int
main(int arg, char **argv)
{
if (tpool_create(5) != 0) {
printf("tpool_create failed\n");
exit(1);
}
int i;
int i_num[10]={0};///使用數組不使用變量的原因是,傳入線程後,值可能會變化。
/*
例如如果使用變量 i_num = 0;
for (i = 0; i < 10; ++i) {///添加10個任務到線程池
tpool_add_work(func, (void*)(&i_num));
}
則可能傳入的i_num的值不是期望的。
*/
for(i=0;i<10;++i)
{
i_num[i]=i;
}
for (i = 0; i < 10; ++i) {///添加10個任務到線程池
tpool_add_work(func, (void*)(&(i_num[i])));
}
sleep(2);
tpool_destroy();
return 0;
}
----------------test.c---------------------
運行結果如下圖所示: