线程池的C++实现

本篇文章用来学习和实现轻松掌握C++线程池:从底层原理到高级应用

代码如下:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
#include <queue>
#include <atomic>
#include <chrono>

using namespace std;

struct Task {
    int priority;
    void operator()() {
        std::cout << "Task executed with priority " << priority << std::endl;
    }
};

//优先队列弹出元素时从堆顶往下弹,按照下面的写法,priority大的在顶部,先弹出。
struct LessByPriority {
    bool operator()(const Task& lhs, const Task& rhs) const {
        return lhs.priority < rhs.priority;
    }
};

class ThreadPool {
public:
    ThreadPool(size_t threadCount) : terminate(false), threadCount(threadCount), taskCount(0), completedTaskCount(0), startTime(chrono::steady_clock::now()) {
        for (size_t threadNum = 0; threadNum < threadCount; ++threadNum) {
//成员函数指针,必须在前面加&,普通函数若想表示函数指针,可加&也可以不加。学一下构造thread的几种方法。
            threads.emplace_back(&ThreadPool::threadFunc, this, threadNum);
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    }

    ~ThreadPool() {
        terminate = true;
        condition.notify_all();
        for (thread& th : threads) {
            if (th.joinable()) {
                th.join();
            }
        }
    }

    void addTask(const Task& task) {
        {
            taskQueue.emplace(task);
            taskCount++;
        }
        condition.notify_one();//每往任务队列中加入一个任务,就通知线程池处理一个
    }

    size_t getCompletedTaskCount() const {
        return completedTaskCount.load();
    }

    double getRunningTimeInSeconds() const {
        chrono::duration<double> duration = chrono::steady_clock::now() - startTime;
        return duration.count();
    }

private:
    void threadFunc(int threadNum) {
                std::cout << "threadFunc " << threadNum << " is ready" << "\n";
        while (true) {
            Task task;
            {
                unique_lock<mutex> lock(queueMutex);
//几个线程都在这里排队等待,当外部调用condition.notify_one();时,操作系统一般是调用排队的最前面的线程
                condition.wait(lock, [this]() { return!taskQueue.empty() || terminate; });

                if (terminate && taskQueue.empty()) {
                    break;
                }

                task = taskQueue.top();
                taskQueue.pop();
            }
            task(); // Execute the task.
            std::cout << "Execute the task with threadNum " << threadNum << "\n";
            completedTaskCount++;
        }
    }

    std::vector<std::thread> threads;

//定义优先队列来存任务,底层容器选择vector,通过比较字段priority来决定优先级
    std::priority_queue<Task, std::vector<Task>, LessByPriority> taskQueue;
    std::mutex queueMutex;
    std::condition_variable condition;

public:
//不需要定义原子操作,直接访问更简洁
    size_t threadCount;
    size_t taskCount;

private:
//定义原子变量,保证线程安全
    atomic<bool> terminate;
    atomic<size_t> completedTaskCount;

    chrono::steady_clock::time_point startTime;
};

int main() {
    ThreadPool pool(5);
    std::cout << "ThreadPool pool OK" << "\n\n";
    for (int i = 0; i < 10; ++i) {
        Task task;
        task.priority = i;
        pool.addTask(task);
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout << "\n";
    std::cout << "Thread count: " << pool.threadCount << std::endl;
    std::cout << "Task count: " << pool.taskCount << std::endl;
    std::cout << "Completed task count: " << pool.getCompletedTaskCount() << std::endl;
    std::cout << "Running time: " << pool.getRunningTimeInSeconds() << " seconds" << std::endl;
    return 0;
}

执行时要加-pthread,结果是:

$ g++ -pthread 线程池.cpp 
$ ./a.out 
threadFunc 0 is ready
threadFunc 1 is ready
threadFunc 2 is ready
threadFunc 3 is ready
threadFunc 4 is ready
ThreadPool pool OK

Task executed with priority 0
Execute the task with threadNum 0
Task executed with priority 1
Execute the task with threadNum 1
Task executed with priority 2
Execute the task with threadNum 2
Task executed with priority 3
Execute the task with threadNum 3
Task executed with priority 4
Execute the task with threadNum 4
Task executed with priority 5
Execute the task with threadNum 0
Task executed with priority 6
Execute the task with threadNum 1
Task executed with priority 7
Execute the task with threadNum 2
Task executed with priority 8
Execute the task with threadNum 3
Task executed with priority 9
Execute the task with threadNum 4

Thread count: 5
Task count: 10
Completed task count: 10
Running time: 8.50287 seconds

注:
①关于优先队列,task本身没有定义顺序。这里每次队列里有一个任务时就处理了,并未体现出多个任务需要调度时,按优先级高的先进行处理。但这么定义排序的写法是没错的。见下:

#include <iostream>
#include <queue>
#include <vector>

// 自定义比较函数 LessByPriority
struct LessByPriority {
    bool operator()(int a, int b) {
        return a < b; // 优先级低的排在前面,如果要优先级高的排在前面,则改为 a < b
    }
};

int main() {
    std::priority_queue<int, std::vector<int>, LessByPriority> pq;

    // 逐个插入元素
    pq.push(5);
    pq.push(7);
    pq.push(2);
    pq.push(9);
    pq.push(3);

    // 输出队列中排好序的结果
    std::cout << "Priority Queue sorted result: ";
    while (!pq.empty()) {
        std::cout << pq.top() << " ";
        pq.pop();
    }
    std::cout << std::endl;

    return 0;
}

结果是:

Priority Queue sorted result: 9 7 5 3 2 

②代码中的threads.emplace_back不可以替代为thread.push_back。
因为push_back 接受容器的元素类型的对象,并将其拷贝(左值)或移动(右值)到容器的末尾。
而emplace_back接受构造函数的参数,并在容器的末尾直接构造一个新元素,而不需要创建临时对象。
括号里的内容是参数,不是对象。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码到程攻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值