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

背景

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

实现思路

接口如下:

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;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
线程池是一种用于管理和复用线程的技术,它可以提高线程的利用率和性能。下面是使用线程池创建线程的步骤: 1. 导入相关的库:首先,你需要导入相关的库,如`java.util.concurrent.Executors`和`java.util.concurrent.ExecutorService`。 2. 创建线程池:使用`Executors`类的静态方法之一来创建一个线程池。常用的方法有: - `newFixedThreadPool(int nThreads)`:创建一个固定大小的线程池,其中包含指定数量的线程。 - `newCachedThreadPool()`:创建一个可缓存的线程池线程数量根据需要自动调整。 - `newSingleThreadExecutor()`:创建一个单线程的线程池,保证任务按顺序执行。 3. 提交任务:使用`ExecutorService`接口的`submit()`方法来提交任务给线程池。你可以将任务表示为实现了`Runnable`接口或`Callable`接口的类。 4. 关闭线程池:在不再需要线程池时,应该调用`ExecutorService`接口的`shutdown()`方法来关闭线程池。这将停止接受新任务,并等待所有已提交的任务完成。 下面是一个示例代码,演示了如何使用线程池创建线程: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { // 创建一个固定大小的线程池 ExecutorService executor = Executors.newFixedThreadPool(5); // 提交任务给线程池 for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("Task " + (i + 1)); executor.submit(worker); } // 关闭线程池 executor.shutdown(); } } class WorkerThread implements Runnable { private String taskName; public WorkerThread(String taskName) { this.taskName = taskName; } @Override public void run() { System.out.println("Task " + taskName + " is being executed."); // 执行任务的代码 } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

老黄叔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值