使用C++STL的并发接口完成线程池

  最近两天看了以下《The C++ Standard library》里介绍的并发模型。今天搞了一下午,排查了bug,终于搞定了:

  总体来讲还是比pthread提供的接口要简洁。

  定义task

class task
{
public:
    virtual void execute()=0;
};

  threadpool.h

#ifndef MATHREADPOOL_H
#define MATHREADPOOL_H
#include <queue>
#include "common.h"
#include <vector>
#include <condition_variable>
#include <mutex>
#include <future>
#include <memory>

namespace manch1n
{
using taskSPtr = std::shared_ptr<manch1n::task>;
class mathreadpool : uncopyable
{
public:
    using lockGuard = std::lock_guard<std::mutex>;
    using uniqueLock = std::unique_lock<std::mutex>;

    explicit mathreadpool(size_t nthreads = 4);
    void initAndRun();
    void pushTask(taskSPtr &);
    bool isEmpty();

private:
    static void *routine(void *arg);

    taskSPtr popTask();
    std::vector<std::thread::id> _threads;
    std::queue<taskSPtr> _tasks;
    size_t _nthreads;
    std::mutex _mutex;
    std::condition_variable _condition;
};

} // namespace manch1n

#endif //MATHREADPOOL_H

  threadpool.cc

#include "mathreadpool.h"

namespace manch1n
{
mathreadpool::mathreadpool(size_t nthreads) : _nthreads(nthreads)
{
}

void mathreadpool::initAndRun()
{
    for (int i = 0; i < _nthreads; ++i)
    {
        std::thread t(routine, this);
        t.detach();
        _threads.push_back(t.get_id());
    }
}

void *mathreadpool::routine(void *arg)
{
    mathreadpool &pool = *static_cast<mathreadpool *>(arg);
    while (1)
    {
        taskSPtr ptask = pool.popTask();
        ptask->execute();
    }
    return NULL;
}

void mathreadpool::pushTask(taskSPtr &t)
{
    {
        lockGuard lock(_mutex);
        _tasks.push(t);
    }
    _condition.notify_one();
}

taskSPtr mathreadpool::popTask()
{
    uniqueLock lock(_mutex);
    _condition.wait(lock,[this](){return !this->isEmpty();});
    taskSPtr p(_tasks.front());
    _tasks.pop();
    return p;
}

bool mathreadpool::isEmpty()
{
    return _tasks.empty();
}

} // namespace manch1n

  测试一下:

  

#include <iostream>
#include <iomanip>
#include <unistd.h>
#include "mathreadpool.h"
using namespace std;
using namespace manch1n;

class drive1:public manch1n::task
{
public:
    virtual void execute() override
    {
        cout<<s<<endl;
    }
    string s="drive1";
};

class drive2:public manch1n::task
{
public:
    virtual void execute() override
    {
        cout<<s<<endl;
    }
    string s="drive2";
};

int main(int argc, char **argv)
{
    taskSPtr d1=make_shared<drive1>();
    taskSPtr d2=make_shared<drive2>();
    mathreadpool pool(4);
    pool.initAndRun();
    pool.pushTask(d1);
    pool.pushTask(d2);
    ::pause();
    return 0;
}

  输出:

[manch1n@centos7 build]$ ./benchmark 
drive2
drive1
^C
[manch1n@centos7 build]$ ./benchmark 
drive1
drive2
^C
[manch1n@centos7 build]$ ./benchmark 
drive1
drive2