一个支持投递到指定线程的线程池

本文介绍了一种特殊的线程池实现方法,该方法允许用户指定任务执行的具体线程,以确保任务处理的顺序性。通过为每个线程分配独立的任务队列,并允许使用无锁队列来提高性能。

背景

​ 常见的线程池实现一般类似多生产者多消费者场景,生产者将任务投递至线程池,而不需要关心这个任务最终在哪个线程上执行,但是在某些特殊场景下,比如某一个对象产生的任务处理需要保证顺序,这样传统的线程池就没有办法满足这种需求,于时考虑实现一种可支持将任务投递至指定线程的线程池。

实现思路

接口如下:

void exec(std::function<void()> &&task, int trdNo = -1)

1.线程池在创建时为每个线程创建一个队列。

2.正常情况下,只需要传入task,这时会随机将task扔到某个线程的队列。

3.当用户传入trdNo时,则投递到对应的线程的队列。

4.如果能保证对应线程的生产者只会在一个线程,可将队列换成无锁队列增加性能

源码实现

#include <vector>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <random>
class ThreadPool
{
public:
    void start(uint16_t trdNum)
    {
        if (_start)
        {
            return;
        }
        _start = true;
        _trdNum = trdNum;
        for (int i = 0; i < trdNum; ++i)
        {
            _trds.emplace_back(std::make_unique<std::thread>(std::bind(&ThreadPool::process, this, i)));
            _cvs.emplace_back(std::make_unique<std::condition_variable> ());
            _mtx.emplace_back(std::make_unique<std::mutex>());
            _trdTasks.emplace_back(std::list < std::function<void()>>());
        }
    }
     //如果trdNo为-1 随机扔到哪个线程的队列
    void exec(std::function<void()> &&task, int trdNo = -1)
    {
        if (!_start)
        {
            return;
        }
        uint16_t no = 0;
        if (-1 == trdNo)
        {
            no = getTrdNo();
            printf("get no:%d \n", no);
        }
        else
        {
            no = trdNo % _trdNum;
        }
        std::lock_guard<std::mutex> lock(*_mtx[no]);
        _trdTasks[no].emplace_back(task);
        _cvs[no]->notify_one();
    }
    void stop()
    {
        _start = false;
        for (int i = 0; i < _trdNum; ++i)
        {
            _cvs[i]->notify_all();
        }
         for (const auto& trd: _trds)
        {
            trd->join();
        }
    }

private:
    void process(int trdNo)
    {
        while (_start)
        {
            std::function<void()> task = nullptr;
            {
                std::unique_lock<std::mutex> lock(*_mtx[trdNo]);
                while (_trdTasks[trdNo].empty() && _start)
                {
                    _cvs[trdNo]->wait(lock);
                }

                if (!_trdTasks[trdNo].empty())
                {
                    task = _trdTasks[trdNo].front();
                    _trdTasks[trdNo].pop_front();
                }
            }
            if (nullptr != task)
            {
                task();
            }
        }
    }
    uint16_t getTrdNo()
    {
        if (1 == _trdNum)
        {
            return 0;
        }
        std::random_device rd; // 用于随机数引擎获得随机种子
        std::mt19937 gen(rd()); // 以rd()为种子的标准mersenne_twister_engine
        std::uniform_int_distribution<int> distribute(0, _trdNum - 1);
        return  distribute(gen) % _trdNum;
    }
    
    uint16_t _trdNum = 0;
    bool _start = false;
    std::vector<std::unique_ptr<std::mutex>> _mtx;
    std::vector<std::unique_ptr<std::condition_variable>> _cvs;
    std::vector<std::unique_ptr<std::thread>> _trds;
    std::vector<std::list<std::function<void()>>> _trdTasks;
};
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老黄叔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值