使用C++11实现线程池的两种方法

概述:什么是线程池?

   因为程序边运行边创建线程是比较耗时的,所以我们通过池化的思想:在程序开始运行前创建多个线程,这样,程序在运行时,只需要从线程池中拿来用就可以了.大大提高了程序运行效率.

如何实现:

   一般线程池都会有以下几个部分构成:

1. 线程池管理器(ThreadPoolManager):用于创建并管理线程池
2. 工作线程(WorkThread): 线程池中线程
3. 任务队列:用于存放没有处理的任务。提供一种缓冲机制。
4. 用于添加任务的接口 

总的来讲,就是先创建几个线程,然后这些线程等待任务队列,不为空拿出任务执行即可(任务可以是对象,也可以是某个函数).

第一种实现:

#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <stdexcept>
#include <condition_variable>
#include <memory> //unique_ptr

const int MAX_THREADS = 1000; //最大线程数目

template <typename T>
class threadPool
{
  public:
    /*默认开一个线程*/
    threadPool(int number = 1);
    ~threadPool();
    /*往请求队列<task_queue>中添加任务<T *>*/
    bool append(T *request);

  private:
    /*工作线程需要运行的函数,不断的从任务队列中取出并执行*/
    static void *worker(void *arg);
    void run();

  private:
    std::vector<std::thread> work_threads; /*工作线程*/
    std::queue<T *> tasks_queue;           /*任务队列*/
    std::mutex queue_mutex;
    std::condition_variable condition;  /*必须与unique_lock配合使用*/
    bool stop;
};

template <typename T>
threadPool<T>::threadPool(int number) : stop(false)
{
    if (number <= 0 || number > MAX_THREADS)
        throw std::exception();
    for (int i = 0; i < number; i++)
    {
        std::cout << "创建第" << i << "个线程 " << std::endl;
        /*
        std::thread temp(worker, this);
        不能先构造再插入
         */
        work_threads.emplace_back(worker, this);
    }
}
template <typename T>
inline threadPool<T>::~threadPool()
{
    /*世上最大 bug 就是因为我写的这个.shit  */
    //work_threads.clear();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        stop = true;
    }
    condition.notify_all();
    for (auto &ww : work_threads)
        ww.join();
}
template <typename T>
bool threadPool<T>::append(T *request)
{
    /*操作工作队列时一定要加锁,因为他被所有线程共享*/
    queue_mutex.lock();
    tasks_queue.push(request);
    queue_mutex.unlock();
    condition.notify_one(); //线程池添加进去了任务,自然要通知等待的线程
    return true;
}
template <typename T>
void *threadPool<T>::worker(void *arg)
{
    threadPool *pool = (threadPool *)arg;
    pool->run();
    return pool;
}
template <typename T>
void threadPool<T>::run()
{
    while (!stop)
    {
        std::unique_lock<std::mutex> lk(this->queue_mutex);
        /* unique_lock() 出作用域会自动解锁 */
        this->condition.wait(lk, [this] { return !this->tasks_queue.empty(); });
        //如果任务队列不为空,就停下来等待唤醒
        if (this->tasks_queue.empty())
        {
            continue;
        }
        else
        {
            T *request = tasks_queue.front();
            tasks_queue.pop();
            if (request)
                request->process();
        }
    }
}
#endif

测试代码:

#include "threadPool.h"
#include<string>
using namespace std;
class Task
{
    public:
    void process()
    {
        cout << "run........." << endl;
    }
};
int main(void)
{
    threadPool<Task> pool(6);
    std::string str;
    while (1)
    {
            Task *tt = new Task();
            //使用智能指针
            pool.append(tt);
            delete tt;
    }
}

第二种实现(适用于需传参,需要将非静态线程函数写在类中的情况):

#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <stdexcept>
#include <condition_variable>
#include <memory> //unique_ptr
#include <functional>

const int MAX_THREADS = 1000; //最大线程数目

typedef std::function<void(void)> Task;

class threadPool
{
  public:
    /*默认开一个线程*/
    threadPool(int number = 1);
    ~threadPool();
    /*往请求队列<task_queue>中添加任务<T *>*/
    bool append(Task task);

  private:
    /*工作线程需要运行的函数,不断的从任务队列中取出并执行*/
    static void *worker(void *arg);
    void run();

  private:
    std::vector<std::thread> work_threads; /*工作线程*/
    std::queue<Task> tasks_queue;           /*任务队列*/

    std::mutex queue_mutex;
    std::condition_variable condition; /*必须与unique_lock配合使用*/
    bool stop;
};

threadPool::threadPool(int number) : stop(false)
{
    if (number <= 0 || number > MAX_THREADS)
        throw std::exception();
    for (int i = 0; i < number; i++)
    {
        std::cout << "创建第" << i << "个线程 " << std::endl;
        work_threads.emplace_back(threadPool::worker, this);
    }
}

inline threadPool::~threadPool()
{
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        stop = true;
    }
    condition.notify_all();
    for (auto &ww : work_threads)
        ww.join();
}

bool threadPool::append(Task task)
{
    /*操作工作队列时一定要加锁,因为他被所有线程共享*/
    queue_mutex.lock();
    tasks_queue.push(task);
    queue_mutex.unlock();
    condition.notify_one(); //线程池添加进去了任务,自然要通知等待的线程
    return true;
}
void *threadPool::worker(void *arg)
{
    threadPool *pool = (threadPool *)arg;
    pool->run();
    return pool;
}
void threadPool::run()
{
    while (!stop)
    {
        std::unique_lock<std::mutex> lk(this->queue_mutex);
        /* unique_lock() 出作用域会自动解锁 */
        this->condition.wait(lk, [this] { return !this->tasks_queue.empty(); });
        //如果任务队列不为空,就停下来等待唤醒
        if (this->tasks_queue.empty())
        {
            continue;
        }
        else
        {
            Task task = tasks_queue.front();
            tasks_queue.pop();
            task();
        }
    }
}
#endif

测试代码:

#include "threadPool_2.h"
using namespace std;
class Test
{
  public:
    void process_no_static_bind(const int i, const int j) /*推荐使用*/
    {
        cout << "bind:  i==" << i << " "
             << "j==" << j << endl;
    }
};
int main(void)
{
    threadPool pool(6);
    Test tt_bind;
    while (true)
    {
        pool.append(std::bind(&Test::process_no_static_bind, &tt_bind, 3, 4));
    }
}

 

posted @ 2021-01-29 16:37  OFSqueque  阅读(648)  评论(0编辑  收藏  举报