线程池通过pthread_create创建指定数量的线程,线程函数中实现一个循环,循环中调用worker实现不同的功能。每一个任务(worker)中维护有该worker的回调函数、回调函数的参数、任务列表(worker队列)。每一个线程创建后,使用pthread_cond_wait进行阻塞,等待任务列表中有任务进入。
根据业务需要,实现了一个线程池,这个线程池在c++实现时,遇到一个问题:使用c++的普通成员函数不能用作pthread_create函数的线程函数。因为在c语言中线程函数为全局函数,因此,在c++中,pthread_create函数也一定要为static。
因为pthread_create的线程函数为static,因此,在线程中如果需要调用普通成员函数来实现相关的业务逻辑,一个通用的做法是:将类的this指针传给这个静态的线程函数,在这个函数中使用指针调用相关的函数。
示例如下:
注意环境条件与互斥锁的使用
ThreadPool.h头文件:
<pre name="code" class="cpp">#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <assert.h>
#include <map>
typedef struct worker{
//任务回调函数
void (*process)(void * arg1, void * arg2, void * arg3, void * arg4);
void * arg1;
void * arg2;
void * arg3;
void * arg4;
struct worker *next;
} ThreadWorker;
class ThreadPool
{
public:
void ThreadPoolInit();
void ThreadPoolDestroy();
void AddWorker(void (*process)(void * ,void *, void *, void *), void * arg1, void * arg2, void * arg3, void * arg4);
int GetWorkerNum();
ThreadPool(int thread_num);
~ThreadPool() {}
private:
static void * RunHelper(void *);
pthread_mutex_t m_queueLock;
pthread_cond_t m_queueReady;
void * __thread_loop(void * arg);
ThreadWorker * m_workerHead;
pthread_t * m_threadIdArray;
int m_threadNum;
int m_workerSize;
bool m_shutDown;
};
#endif
ThreadPool.cpp源文件
<pre name="code" class="cpp">#include "ThreadPool.h"
ThreadPool::ThreadPool(int thread_num):m_threadNum(thread_num),
m_workerSize(0),
m_workerHead(0),
m_threadIdArray(0)
{
m_shutDown = false;
pthread_mutex_init(&m_queueLock, NULL);
pthread_cond_init(&m_queueReady, NULL);
m_threadIdArray = (pthread_t*)malloc(m_threadNum * sizeof(pthread_t));
}
void ThreadPool::ThreadPoolInit()
{
for (int i = 0; i < m_threadNum; ++i)
{
//RunHelper为静态函数,参数传入this指针
pthread_create(&m_threadIdArray[i], NULL, &RunHelper, (void *)this);
}
return;
}
void ThreadPool::ThreadPoolDestroy()
{
if(m_shutDown)
return;
m_shutDown = true;
pthread_cond_broadcast(&m_queueReady);
for (int i = 0; i < m_threadNum; ++i)
{
pthread_join(m_threadIdArray[i], NULL);
}
free(m_threadIdArray);
m_threadIdArray = NULL;
ThreadWorker * worker = NULL;
while(m_workerHead != NULL)
{
worker = m_workerHead;
m_workerHead = m_workerHead->next;
free(worker);
}
pthread_mutex_destroy(&m_queueLock);
pthread_cond_destroy(&m_queueReady);
delete this;
}
void ThreadPool::AddWorker(void (*process)(void * ,void *, void *, void *), void * arg1, void * arg2, void * arg3, void * arg4)
{
ThreadWorker * new_worker = (ThreadWorker *)malloc(sizeof(ThreadWorker));
new_worker->process = process;
new_worker->arg1 = arg1;
new_worker->arg2 = arg2;
new_worker->arg3 = arg3;
new_worker->arg4 = arg4;
new_worker->next = NULL;
pthread_mutex_lock(&m_queueLock);
ThreadWorker * wk = m_workerHead;
if (wk == NULL)
{
m_workerHead = new_worker;
}else
{
while(wk->next != NULL)
wk = wk->next;
wk->next = new_worker;
}
assert(m_workerHead != NULL);
m_workerSize++;
pthread_mutex_unlock(&m_queueLock);
pthread_cond_signal(&m_queueReady);
return;
}
int ThreadPool::GetWorkerNum()
{
return m_workerSize;
}
void * ThreadPool::__thread_loop(void * arg)
{
#ifdef DEBUG
printf("starting thread 0x%x\n", pthread_self());
#endif
while(1)
{
pthread_mutex_lock(&m_queueLock);
while(m_workerSize == 0 && !m_shutDown)
{
#ifdef DEBUG
printf("thread 0x%x is waiting\n", pthread_self());
#endif
//当pthread_cond_wait时,m_queueLock解锁,当pthread_cond_wait执行时,m_queueLock加锁
pthread_cond_wait(&m_queueReady, &m_queueLock);
}
if (m_shutDown)
{
pthread_mutex_unlock(&m_queueLock);
#ifdef DEBUG
printf("thread 0x%x will exit\n", pthread_self());
#endif
pthread_exit(NULL);
}
assert(m_workerSize != 0);
assert(m_workerHead != NULL);
m_workerSize--;
ThreadWorker * worker = m_workerHead;
m_workerHead = m_workerHead->next;
pthread_mutex_unlock(&m_queueLock);
(*(worker->process))(worker->arg1, worker->arg2, worker->arg3, worker->arg4);
free(worker);
worker = NULL;
}
return NULL;
}
//静态函数,用于pthread_create调用
void * ThreadPool::RunHelper(void * arg)
{
((ThreadPool *)arg)->__thread_loop(NULL);
return NULL;
}
调用main.cpp仅为参考,不能保证运行:
<pre name="code" class="cpp">#include <cut2mesh/PreFix.h>
#include <merge_area/MergeArea.h>
#include <thread_pool/ThreadPool.h>
extern MeshRegions glob_map_mesh_regions;
//声明任务回调函数
void thread_process_func(void * agr1, void * arg2, void * arg3, void * arg4);
int main(int argc, char ** argv)
{
char * input_path = NULL;
char * output_path = NULL;
char * input_name = NULL;
int thread_num = 1;
int c;
while((c = getopt(argc, argv, "i::n::o::j::")) != -1)
{
switch(c)
{
case 'i':
input_path = optarg;
break;
case 'n':
input_name = optarg;
break;
case 'o':
output_path = optarg;
break;
case 'j':
thread_num = atoi(optarg) ? atoi(optarg) : 1;
break;
case '?':
fprintf(stderr, "usage: %s [-i] [-n] [-o] args\n", argv[0]);
return -1;
break;
}
}
if (input_path == NULL && output_path == NULL && input_name == NULL)
{
fprintf(stderr, "[-i] [-o] [-n] options can not be empty!\n");
return -1;
}
Run_Prefix(input_path, output_path, input_name);
char mesh_names[255][glob_map_mesh_regions.size()];
Regions regions_array[glob_map_mesh_regions.size()];
//定义一个线程池对象
ThreadPool * pool = new ThreadPool(thread_num);
//初始化线程池,生成线程
pool->ThreadPoolInit();
int i = 0;
BOOST_FOREACH(MeshRegionsPair & pair, glob_map_mesh_regions)
{
strcpy(mesh_names[i], pair.first.c_str());
regions_array[i] = pair.second;
//向内存池中加入任务
pool->AddWorker(thread_process_func, output_path, input_name, mesh_names[i], ®ions_array[i]);
++i;
}
while(pool->GetWorkerNum() != 0)
{
double progress = (glob_map_mesh_regions.size() - pool->GetWorkerNum())/glob_map_mesh_regions.size() * 100;
printf("\rprocessing: %f%%", progress);
sleep(1);
}
pool->ThreadPoolDestroy();
printf("\rprocessing: 100%%\n");
return 0;
}
void thread_process_func(void * arg1, void * arg2, void * arg3, void * arg4)
{
//由于都是void *,将其转为业务函数能调用的参数
char * output_path = (char *)arg1;
char * name = (char *)arg2;
char * mesh = (char *)arg3;
Regions * regions = (Regions *)arg4;
#ifdef DEBUG
printf("now doing %s\n", mesh);
#endif
//业务函数
Regions result = RunMergeArea(*regions);
#ifdef DEBUG
printf("now outputing %s\n", mesh);
#endif
Write_One_Mesh(output_path, name, mesh, result);
}