C++ 11은 간단한 스레드 풀을 구현합니다.

스레드 풀은 작업이 대기열에 추가된 다음 스레드가 생성된 후 자동으로 시작되는 멀티스레딩의 한 형태입니다. 스레드 풀 스레드는 모두 백그라운드 스레드입니다. 각 스레드는 기본 스택 크기를 사용하고 기본 우선 순위로 실행되며 다중 스레드 아파트에 있습니다. 스레드가 관리 코드 에서 유휴 상태인 경우 (예: 이벤트 대기) 스레드 풀은 다른 작업자 스레드를 삽입하여 모든 프로세서를 바쁜 상태로 유지합니다. 모든 스레드 풀 스레드가 항상 사용 중이지만 대기열에 보류 중인 작업이 포함된 경우 스레드 풀은 잠시 후 다른 작업자 스레드를 생성하지만 스레드 수가 최대값을 초과하지 않습니다. 최대값을 초과하는 스레드는 대기열에 추가될 수 있지만 다른 스레드가 완료될 때까지 시작되지 않습니다.

C++11 표준은 스레드를 지원하지만 스레드 풀은 지원하지 않습니다. 이 기사에서는 C++11을 사용하여 우선순위 없이 가장 간단한 스레드 풀을 구현합니다.

C++ 11은 간단한 스레드 풀을 구현합니다.

C++11에 사용된 새로운 기능은 다음과 같습니다.

표준::unique_lock
표준::뮤텍스
표준::atomic_bool
표준::스레드
표준::미래
표준::조건_변수
표준::함수
표준::앞으로
표준::packaged_task
표준::make_shared

auto, decltype 자동 유형 공제

스레드로부터 안전한 큐

내부 개체에 액세스하기 위한 스레드 안전성을 보장하기 위해 std::queue<T>를 기반으로 구현되었습니다.

/**
 * @brief  线程安全队列
 * @author GGX
 * @date   2023-08-13
 */
template <typename T>
class CSateQueue
{
public:
    CSateQueue() = default;
    ~CSateQueue() {}

    /**
     * @brief  队列是否为空
     * @param  无
     * @return true 空,false 非空
     * @author GGX
     * @date   2023-08-19
     */
    bool empty() const
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_queue.empty();
    }

    /**
     * @brief  队列是否为空
     * @param  无
     * @return size_t 队列大小
     * @author GGX
     * @date   2023-08-19
     */
    size_t size() const
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_queue.size();
    }

    /**
     * @brief  压栈
     * @param  对象
     * @return 无
     * @author GGX
     * @date   2023-08-19
     */
    void push(T &t)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_queue.emplace(t);
    }

    /**
     * @brief  出栈
     * @param  对象
     * @return true 成功,false 失败
     * @author GGX
     * @date   2023-08-19
     */
    bool front(T &t)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        if (m_queue.empty())
        {
            return false;
        }

        t = std::move(m_queue.front());
        m_queue.pop();
        return true;
    }
private:
    // 利用模板函数构造队列
    std::queue<T> m_queue;
    // 互斥量,可修改
    mutable std::mutex m_mutex;
};

스레드 풀

영구 스레드, 작업이 있을 때만 스레드를 시작합니다.

/**
 * @brief  线程池
 * @author GGX
 * @date   2023-08-13
 */
class ThreadPool
{
public:

    /**
     * @brief  构造函数,默认六个线程
     * @param  [in] size 线程数目
     * @return
     * @author GGX
     * @date   2023-08-19
     */
    explicit ThreadPool(size_t size = 6): m_size(size)
    {
        m_active = false;
    }

    ~ThreadPool()
    {
        stop();
    }

    /**
     * @brief  启动线程池
     * @param  无
     * @return 无
     * @author GGX
     * @date   2023-08-19
     */
    void start()
    {
        //标记线程启动
        m_active = true;
        m_threads.reserve(m_size);
        for (size_t i = 0; i < m_size; i++)
        {
            //创建线程池
            m_threads.emplace_back(ThreadPool::work, this);
        }
        std::cout << "ThreadPool start" << std::endl;
    }

    /**
     * @brief  停止线程池
     * @param  无
     * @return 无
     * @author GGX
     * @date   2023-08-19
     */
    void stop()
    {
        //标记线程停止
        m_active = false;
        //唤醒所有线程
        m_cv.notify_all();
        for (thread &th : m_threads)
        {
            //优雅的退出线程
            if (th.joinable())
            {
                th.join();
            }
        }
        std::cout << "ThreadPool stop" << std::endl;
    }

    void work()
    {
        std::function<void()> func; // 定义基础函数类func
        bool dequeued = false; // 是否正在取出队列中元素
        while (m_active)
        {
            dequeued = false;
            {
                std::unique_lock<std::mutex> lock(m_mutex);
                //判断任务队列是否为空,线程是否已停止
                auto funcR = [](CSateQueue<std::function<void()>> &tasks,
                                std::atomic_bool & bActive)->bool
                {
                    return !tasks.empty() || !bActive;
                };
                //等待线程被唤醒
                m_cv.wait(lock, std::bind(funcR, std::ref(m_tasks), std::ref(m_active)));

                if (!m_active)
                {
                    break;
                }

                dequeued = m_tasks.front(func);
            }
            //取到任务,则运行
            if (dequeued)
            {
                func();
            }
        }
    }

    /**
     * @brief  提交任务,让线程执行
     * @param  [in] f 任务
    * @param  [in] ...args 可变参
     * @return auto 返回值类型,自动推导
     * @author GGX
     * @date   2023-08-19
     */
    template <typename F, typename ...Args>
    auto submit(F && f, Args && ...args)->std::future<decltype(f(args...))>
    {
        //返回值类型
        using returnType = decltype(f(args...))();
        //函数包
        std::function<returnType> func =
            std::bind(std::forward<F>(f), std::forward<Args>(args)...);
        //包装任何可调用函数对象
        auto fu_ptr = std::make_shared<std::packaged_task<returnType>> (func);

        std::function<void()> task = [fu_ptr]
        {
            (*fu_ptr)();
        };
        //函数放入队列
        m_tasks.push(task);
        //唤醒一个线程
        m_cv.notify_one();
        //返回结果
        return fu_ptr->get_future();
    }

private:
    size_t m_size;	//线程大小
    std::atomic_bool m_active;	//线程是否运行,原子变量
    vector<thread> m_threads;	//线程容器
    std::condition_variable m_cv;//条件变量,唤醒线程
    std::mutex m_mutex;	//互斥量,保证线程安全
    CSateQueue<std::function<void()>> m_tasks; //任务队列
};

통화 예

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <vector>
#include <queue>
#include <functional>
#include <future>
#include <random>

using namespace std;

/**
 * @brief  线程安全队列
 * @author GGX
 * @date   2023-08-13
 */
template <typename T>
class CSateQueue
{
public:
    CSateQueue() = default;
    ~CSateQueue() {}

    /**
     * @brief  队列是否为空
     * @param  无
     * @return true 空,false 非空
     * @author GGX
     * @date   2023-08-19
     */
    bool empty() const
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_queue.empty();
    }

    /**
     * @brief  队列是否为空
     * @param  无
     * @return size_t 队列大小
     * @author GGX
     * @date   2023-08-19
     */
    size_t size() const
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_queue.size();
    }

    /**
     * @brief  压栈
     * @param  对象
     * @return 无
     * @author GGX
     * @date   2023-08-19
     */
    void push(T &t)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_queue.emplace(t);
    }

    /**
     * @brief  出栈
     * @param  对象
     * @return true 成功,false 失败
     * @author GGX
     * @date   2023-08-19
     */
    bool front(T &t)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        if (m_queue.empty())
        {
            return false;
        }

        t = std::move(m_queue.front());
        m_queue.pop();
        return true;
    }
private:
    // 利用模板函数构造队列
    std::queue<T> m_queue;
    // 互斥量,可修改
    mutable std::mutex m_mutex;
};


/**
 * @brief  线程池
 * @author GGX
 * @date   2023-08-13
 */
class ThreadPool
{
public:

    /**
     * @brief  构造函数,默认六个线程
     * @param  [in] size 线程数目
     * @return
     * @author GGX
     * @date   2023-08-19
     */
    explicit ThreadPool(size_t size = 6): m_size(size)
    {
        m_active = false;
    }

    ~ThreadPool()
    {
        stop();
    }

    /**
     * @brief  启动线程池
     * @param  无
     * @return 无
     * @author GGX
     * @date   2023-08-19
     */
    void start()
    {
        //标记线程启动
        m_active = true;
        m_threads.reserve(m_size);
        for (size_t i = 0; i < m_size; i++)
        {
            //创建线程池
            m_threads.emplace_back(ThreadPool::work, this);
        }
        std::cout << "ThreadPool start" << std::endl;
    }

    /**
     * @brief  停止线程池
     * @param  无
     * @return 无
     * @author GGX
     * @date   2023-08-19
     */
    void stop()
    {
        //标记线程停止
        m_active = false;
        //唤醒所有线程
        m_cv.notify_all();
        for (thread &th : m_threads)
        {
            //优雅的退出线程
            if (th.joinable())
            {
                th.join();
            }
        }
        std::cout << "ThreadPool stop" << std::endl;
    }

    void work()
    {
        std::function<void()> func; // 定义基础函数类func
        bool dequeued = false; // 是否正在取出队列中元素
        while (m_active)
        {
            dequeued = false;
            {
                std::unique_lock<std::mutex> lock(m_mutex);
                //判断任务队列是否为空,线程是否已停止
                auto funcR = [](CSateQueue<std::function<void()>> &tasks,
                                std::atomic_bool & bActive)->bool
                {
                    return !tasks.empty() || !bActive;
                };
                //等待线程被唤醒
                m_cv.wait(lock, std::bind(funcR, std::ref(m_tasks), std::ref(m_active)));

                if (!m_active)
                {
                    break;
                }

                dequeued = m_tasks.front(func);
            }
            //取到任务,则运行
            if (dequeued)
            {
                func();
            }
        }
    }

    /**
     * @brief  提交任务,让线程执行
     * @param  [in] f 任务
    * @param  [in] ...args 可变参
     * @return auto 返回值类型,自动推导
     * @author GGX
     * @date   2023-08-19
     */
    template <typename F, typename ...Args>
    auto submit(F && f, Args && ...args)->std::future<decltype(f(args...))>
    {
        //返回值类型
        using returnType = decltype(f(args...))();
        //函数包
        std::function<returnType> func =
            std::bind(std::forward<F>(f), std::forward<Args>(args)...);
        //包装任何可调用函数对象
        auto fu_ptr = std::make_shared<std::packaged_task<returnType>> (func);

        std::function<void()> task = [fu_ptr]
        {
            (*fu_ptr)();
        };
        //函数放入队列
        m_tasks.push(task);
        //唤醒一个线程
        m_cv.notify_one();
        //返回结果
        return fu_ptr->get_future();
    }

private:
    size_t m_size;	//线程大小
    std::atomic_bool m_active;	//线程是否运行,原子变量
    vector<thread> m_threads;	//线程容器
    std::condition_variable m_cv;//条件变量,唤醒线程
    std::mutex m_mutex;	//互斥量,保证线程安全
    CSateQueue<std::function<void()>> m_tasks; //任务队列
};

std::random_device rd; // 真实随机数产生器
std::mt19937 mt(rd()); //生成计算随机数mt
std::uniform_int_distribution<int> dist(-1000, 1000); //生成-1000到1000之间的离散均匀分布数
auto rnd = std::bind(dist, mt);

/**
 * @brief  测试线程池
 * @author GGX
 * @date   2023-08-13
 */
class CTest
{
public:

    void simulate_hard_computation()
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(2000 + rnd()));
    }

    void multiply(const int a, const int b)
    {
        simulate_hard_computation();
        const int res = a * b;
        std::cout << "multiply thid: " << std::this_thread::get_id() << std::endl;
        std::cout << a << " * " << b << " = " << res << std::endl;
    }
    void multiply_output(int &out, const int a, const int b)
    {
        simulate_hard_computation();
        out = a * b;
        std::cout << "multiply_output thid: " << std::this_thread::get_id() << std::endl;
        std::cout << a << " * " << b << " = " << out << std::endl;
    }

    int multiply_return(const int a, const int b)
    {
        simulate_hard_computation();
        const int res = a * b;
        std::cout << "multiply_return thid: " << std::this_thread::get_id() << std::endl;
        std::cout << a << " * " << b << " = " << res << std::endl;
        return res;
    }
};

void example()
{
    CTest a;
    ThreadPool pool(6);
    pool.start();
    //对象方法,因此需要绑定对象
    std::function<void(int, int)> multiply =
        std::bind(&CTest::multiply, &a, std::placeholders::_1, std::placeholders::_2);

    for (int i = 1; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            //提交调用
            pool.submit(multiply, i, j);
        }
    }

    auto future = pool.submit(multiply, 3, 10);
    future.get();

    int output_ref;
    std::function<void(int&, int, int)> multiply_output =
        std::bind(&CTest::multiply_output, &a, std::placeholders::_1,
                  std::placeholders::_2, std::placeholders::_3);
    // 使用ref传递的输出参数提交函数
    auto future1 = pool.submit(multiply_output, std::ref(output_ref), 5, 6);
    future1.get();
    std::cout << "Last operation result is equals to " << output_ref << std::endl;

    // 使用return参数提交函数
    std::function<int(int, int)> multiply_return =
        std::bind(&CTest::multiply_return, &a, std::placeholders::_1, std::placeholders::_2);
    auto future2 = pool.submit(multiply_return, 5, 3);
    // 等待乘法输出完成
    int res = future2.get();
    std::cout << "Last operation result is equals to " << res << std::endl;
    pool.stop();
}

int main()
{
    std::cout << "std::thread::hardware_concurrency() "
              << std::thread::hardware_concurrency() << std::endl << std::endl;
    example();
    return 0;
}

산출

 

Supongo que te gusta

Origin blog.csdn.net/qq_40788199/article/details/132383838
Recomendado
Clasificación