Linux C++线程池的实现

9 篇文章 0 订阅

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


 
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值