线程池(C++代码演示)

/*** 线程池实现过程 ***/
/* 创建Task类表示任务 */
class Task {
public:
    /* 使用bind将函数和参数绑定,将返回的函数指针传给Task的成员func */
    /* Task的构造函数为模板方法 */
    template<typename FUNC_T, typename ...ARGS>
    Task(FUNC_T func, ARGS...  args) {
        this->func = bind(func, forward<ARGS>(args)...);
    }
    void run() {
        this->func();
        return ;
    }
    /* 使用function<void()>函数指针来接受bind的返回值 */
    function<void()> func;
};

/* 创建ThreadPool类 */
class ThreadPool {
public:
    ThreadPool(int n = 1) : thread_size(n), starting(false), threads(n) {
        this->start();
        return ;
    }
    /* worker函数可以想象成流水线上的工人, 不停地取任务和执行任务 */
    void worker() {
        /* this_thread::get_id() 可以返回 当前线程的id */
        auto id = this_thread::get_id();
        running[id] = true;
        while (running[id] == true) {
            Task *t = get_task(); // 取任务
            t->run(); // 执行任务
            delete t;
        }
        return ;
    }
    void start() {
        if (starting == true) return ;
        /* 创建thread_size个线程 */
        for (int i = 0; i < thread_size; i++) {
            /* 可以想象成是把工人放进流水线让他们工作 */
            threads[i] = new thread(&ThreadPool::worker, this);
        }
        starting = true;
        return ;
    }
    /* 此方法是将任务添加到任务队列 */
    template<typename FUNC_T, typename ...ARGS>
    void add_task(FUNC_T func, ARGS... args) {
        /* 加锁访问公共资源 */
        unique_lock<mutex> lock(m_mutex);
        tasks.push(new Task(func, forward<ARGS>(args)...));
        /* 通知有任务进入队列 */
        m_cond.notify_one();
        return ;
    }
    /* 此方法是将所有线程停止并清空 */
    void stop() {
        if (starting == false) return ;
        /* 添加threads.size()个停止任务,使所有接到该任务的线程停止 */
        for (int i = 0; i < threads.size(); i++) {
            this->add_task(&ThreadPool::stop_running, this);
        }
        /* 等待所有线程结束 */
        for (int i = 0; i < threads.size(); i++) {
            threads[i]->join();
        }
        /* 清空所有线程 */
        for (int i = 0; i < threads.size(); i++) {
            delete threads[i];
            threads[i] = nullptr;
        }
        starting = false;
        return ;
    }
    /* ThreadPool的析构函数 */
    ~ThreadPool() {
        /* 将所有线程停止并清空 */
        this->stop();
        /* 将任务队列清空 */
        while (!tasks.empty()) {
            delete tasks.front();
            tasks.pop();
        }
        return ;
    }
/* ThreadPool的成员属性 */
private:
    /* 停止任务,作用是使接到该任务的线程停止 */
    void stop_running() {
        auto id = this_thread::get_id();
        running[id] = false;
        return ;
    }
    /* 该函数为工人取任务的方法 */
    Task *get_task() {
        /* 加锁访问公共资源 */
        unique_lock<mutex> lock(m_mutex);
        /* 如果任务队列为空则进入等待 */
        while (tasks.empty()) m_cond.wait(lock);
        Task *t = tasks.front();
        tasks.pop();
        return t;
    }
    int thread_size; // 表示线程个数
    bool starting; // 表示整个线程池是否启动
    std::mutex m_mutex; // 互斥锁
    std::condition_variable m_cond; // 条件信号量
    vector<thread *> threads; // 使用vector存储线程指针
    unordered_map<std::thread::id, bool> running; // 使用unordered_map来表示线程是否在运行
    queue<Task *> tasks; // 任务队列
};



/******   使用样例   ******/
/***  统计5000万以内的素数个数 ***/

bool is_prime(int x) {
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0) return false;
    }
    return true;
}

int prime_count(int l, int r) {
    int ans = 0;
    for (int i = l; i <= r; i++) {
        ans += is_prime(i);
    }
    return ans;
}

void work(int l, int r, int &ret) { 
    cout << this_thread::get_id() << " begin" << endl;
    ret = prime_count(l, r);
    cout << this_thread::get_id() << " done" << endl;
    return ;
}

int main() {
    ThreadPool tp(5);
    #define batch 5000000
    int ret[10];
    for (int i = 0, j = 1; i < 10; i++, j += batch) {
        tp.add_task(work, j, j + batch - 1, ref(ret[i]));
    }
    tp.stop();
    int ans = 0;
    for (auto x : ret) ans += x;
    cout << ans << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值