Linux C++线程池的实现

来源:互联网 发布:空气污染 知乎 编辑:程序博客网 时间:2024/05/17 11:34

线程池通过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], &regions_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);}




0 0
原创粉丝点击