手撕腾讯的tars框架的线程池

文章介绍了C++实现的线程池类ThreadPool,包括其初始化、任务执行、线程数量获取、停止线程池等功能。关键函数如init用于创建线程,exec用于提交任务,stop用于终止线程池。线程池通过队列管理待执行任务,并使用互斥锁和条件变量进行同步。
摘要由CSDN通过智能技术生成

看开源库的线程池

主要看线程池的三部分: init 回调函数 入队函数 (外加一个销毁函数)

而c++线程池,因为类封装在一起,可以先看 成员数据
先上完整代码,这是我稍稍魔改过的

// ThreadPool.h
#ifndef ThreadPool_H
#define ThreadPool_H

#include <cassert> //for assert
#include <future>
#include <functional>
#include <iostream>
#include <queue>
#include <mutex>
#include <memory>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
using namespace std;

void getNow(timeval *tv);
int64_t getNowMs();

#define TNOW getNow()
#define TNOWMS getNowMs()

class ThreadPool
{
public:
    void exec_py(const std::function<void()> &f)
    {
        exec(f);
        return;
    }

    ThreadPool(int size);
    ThreadPool(){};
    virtual ~ThreadPool();
    bool init(size_t num);
    size_t getThreadNum()
    {
        std::unique_lock<std::mutex> lock(_mutex);

        return _threads.size();
    }
    size_t getJobNum()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _tasks.size();
    }
    void stop();
    bool start(size_t num = 1); 
    template <class F, class... Args>
    auto exec(F &&f, Args &&...args) -> std::future<decltype(f(args...))>
    {
        return exec(0, f, args...);
    }
    template <class F, class... Args>
    auto exec(int64_t timeoutMs, F &&f, Args &&...args) -> std::future<decltype(f(args...))>
    {
        int64_t expireTime = (timeoutMs == 0 ? 0 : TNOWMS + timeoutMs);
        using RetType = decltype(f(args...)); 
        auto task = std::make_shared<std::packaged_task<RetType()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));

        TaskFuncPtr fPtr = std::make_shared<TaskFunc>(expireTime); 
        fPtr->_func = [task]() {                                   
            (*task)();
        };

        std::unique_lock<std::mutex> lock(_mutex);
        _tasks.push(fPtr);       
        _condition.notify_one(); 

        return task->get_future();
    }
    bool waitForAllDone(int millsecond = -1);

protected:
    struct TaskFunc
    {
        TaskFunc(uint64_t expireTime) : _expireTime(expireTime)
        {
        }

        std::function<void()> _func;
        int64_t _expireTime = 0; 
    };
    typedef shared_ptr<TaskFunc> TaskFuncPtr;

protected:
    bool get(TaskFuncPtr &task);
    bool isTerminate() { return _bTerminate; }
    void run();

protected:
    queue<TaskFuncPtr> _tasks;
    std::vector<std::thread *> _threads;
    std::mutex _mutex;
    std::condition_variable _condition;
    size_t _threadNum;
    bool _bTerminate;
    std::atomic<int> _atomic{0};
};

#endif // ThreadPool_H

#include "threadpool.h"

ThreadPool::ThreadPool(int size)
    : _threadNum(1), _bTerminate(false)
{
    start(size_t(size));
}

ThreadPool::~ThreadPool()
{
    stop();
}

bool ThreadPool::init(size_t num)
{
    std::unique_lock<std::mutex> lock(_mutex);
    if (!_threads.empty())
    {
        return false;
    }
    if (num < 1)
    {
        _threadNum = 1;
    }
    else
        _threadNum = num;
    return true;
}

void ThreadPool::stop()
{
    {
        std::unique_lock<std::mutex> lock(_mutex);

        _bTerminate = true;

        _condition.notify_all();
    }

    for (size_t i = 0; i < _threads.size(); i++)
    {
        if (_threads[i]->joinable())
        {
            _threads[i]->join();
        }
        delete _threads[i];
        _threads[i] = NULL;
    }

    std::unique_lock<std::mutex> lock(_mutex);
    _threads.clear();
}

bool ThreadPool::start(size_t num)
{
    init(num);
    std::unique_lock<std::mutex> lock(_mutex);

    if (!_threads.empty())
    {
        return false;
    }

    for (size_t i = 0; i < _threadNum; i++)
    {
        _threads.push_back(new thread(&ThreadPool::run, this));
    }
    return true;
}

bool ThreadPool::get(TaskFuncPtr &task)
{
    std::unique_lock<std::mutex> lock(_mutex);
    if (_tasks.empty())
    {
        _condition.wait(lock, [this]
                        { return _bTerminate || !_tasks.empty(); });
    }
    if (_bTerminate)
        return false;
    if (!_tasks.empty())
    {
        task = std::move(_tasks.front()); // 使用了移动语义

        _tasks.pop();

        return true;
    }
    return false;
}

void ThreadPool::run()
{
    while (!isTerminate())
    {
        TaskFuncPtr task;
        bool ok = get(task);
        if (ok)
        {
            ++_atomic;
            try
            {
                if (task->_expireTime != 0 && task->_expireTime < TNOWMS)
                {
                    //超时任务,是否需要处理?
                }
                else
                {
                    task->_func();
                }
            }
            catch (...)
            {
            }
            --_atomic;
            std::unique_lock<std::mutex> lock(_mutex);
            if (_atomic == 0 && _tasks.empty())
            {
                _condition.notify_all();
            }
        }
    }
}

bool ThreadPool::waitForAllDone(int millsecond)
{
    std::unique_lock<std::mutex> lock(_mutex);

    if (_tasks.empty())
        return true;

    if (millsecond < 0)
    {
        _condition.wait(lock, [this]
                        { return _tasks.empty(); });
        return true;
    }
    else
    {
        return _condition.wait_for(lock, std::chrono::milliseconds(millsecond), [this]
                                   { return _tasks.empty(); });
    }
}

int gettimeofday(struct timeval &tv)
{
#if WIN32
    time_t clock;
    struct tm tm;
    SYSTEMTIME wtm;
    GetLocalTime(&wtm);
    tm.tm_year = wtm.wYear - 1900;
    tm.tm_mon = wtm.wMonth - 1;
    tm.tm_mday = wtm.wDay;
    tm.tm_hour = wtm.wHour;
    tm.tm_min = wtm.wMinute;
    tm.tm_sec = wtm.wSecond;
    tm.tm_isdst = -1;
    clock = mktime(&tm);
    tv.tv_sec = clock;
    tv.tv_usec = wtm.wMilliseconds * 1000;

    return 0;
#else
    return ::gettimeofday(&tv, 0);
#endif
}

void getNow(timeval *tv)
{
#if TARGET_PLATFORM_IOS || TARGET_PLATFORM_LINUX

    int idx = _buf_idx;
    *tv = _t[idx];
    if (fabs(_cpu_cycle - 0) < 0.0001 && _use_tsc)
    {
        addTimeOffset(*tv, idx);
    }
    else
    {
        TC_Common::gettimeofday(*tv);
    }
#else
    gettimeofday(*tv);
#endif
}

int64_t getNowMs()
{
    struct timeval tv;
    getNow(&tv);

    return tv.tv_sec * (int64_t)1000 + tv.tv_usec / 1000;
}

    queue<TaskFuncPtr> _tasks; //任务队列
    std::vector<std::thread *> _threads;//线程队列
    std::mutex _mutex;//互斥锁,用来配合条件变量
    std::condition_variable _condition;//条件变量,用来唤醒线程
    size_t _threadNum;//线程池中线程的数量
    bool _bTerminate;  //结束标识符,当想把线程池结束的时候讲这个变量设置为true
    //注:对死循环的任务无效,不过死循环的任务就不要用线程池管理了
    std::atomic<int> _atomic{0}; //原子锁,用来防止虚假唤醒

线程池主要就三个部分,接下来依次介绍

TODO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值