asio模型(io_context 和 thread的使用)

asio模型(io_context 和 thread的使用)

本文借鉴网址

Boost.asio有两种支持多线程的方式:

  • 多个io_context对应多线程(每个线程都有一个io_context,均调用各自的run方法
  • 一个io_context对应多线程(所有线程共用一个io_context,每个线程都调用全局的io_context.run 方法

每个线程一个 I/O Service

让我们先分析第一种方案:在多线程的场景下,每个线程都持有一个io_service (通常的做法是,让线程数和 CPU 核心数保持一致)。那么这种方案有什么特点呢?

  • 在多核的机器上,这种方案可以充分利用多个 CPU 核心。
  • 某个 socket 描述符并不会在多个线程之间共享,所以不需要引入同步机制。
  • 在 event handler 中不能执行阻塞的操作,否则将会阻塞掉io_service所在的线程。

下面实现了一个AsioIoContextPool的简单版线程池

#ifndef IOCONTEXTPOOL_H
#define IOCONTEXTPOOL_H

#include <boost/asio.hpp>
#include <thread>
#include <iostream>
#include <vector>

class AsioIoContextPool
{
public:
    using IOContext = boost::asio::io_context;
    using Work = boost::asio::io_context::work;
    using WorkPtr = std::unique_ptr<Work>;
    AsioIoContextPool(std::size_t size=std::thread::hardware_concurrency() );
    AsioIoContextPool(const AsioIoContextPool&)=delete ;
    AsioIoContextPool &operator=(const AsioIoContextPool &)=delete ;
    boost::asio::io_context &getIOCOntext();
    void stop();
private:
    std::vector<IOContext>      io_context_;
    std::vector<WorkPtr>        works_;
    std::vector<std::thread>    threads_;
    std::size_t                 nextIOContext_;
};

#endif // IOCONTEXTPOOL_H


#include "ioContextPool.h"

AsioIoContextPool::AsioIoContextPool(std::size_t size)
    :io_context_(size),
      works_(size),
      nextIOContext_(0)
{
    for(std::size_t i=0;i<size;i++)
        works_[i] = std::unique_ptr<Work>(new Work(io_context_[i]));

    for(std::size_t i=0;i<io_context_.size();i++)
        threads_.emplace_back([this,i](){
            io_context_[i].run();
        });
}

boost::asio::io_context &AsioIoContextPool::getIOCOntext()
{
    auto &service = io_context_[nextIOContext_++];
    if(nextIOContext_ == io_context_.size())
        nextIOContext_ = 0;
    return service;
}

void AsioIoContextPool::stop()
{
    for(auto& work: works_)
        work.reset();

    for(auto& t: threads_)
        t.join();
}

其中std::thread::hardware_concurrency()来获取硬件支持多少个并发线程

接下来用两个实例,来展示线程池的使用方法:

#include <iostream>
#include <ioContextPool.h>

using namespace std;

int main()
{
    std::mutex mtx;             // protect std::cout
    AsioIoContextPool pool;

    int j=1;
    //只有进行了pool.getIOContext就会分配一个线程
    boost::asio::steady_timer timer{pool.getIOCOntext(), std::chrono::seconds{4}};
    timer.async_wait([&mtx,&j] (const boost::system::error_code &ec)
                      {
                          std::lock_guard<std::mutex> lock(mtx); //锁,为了防止在访问j变量时,下一个线程访问改值
                          for(int i=0;i<10;i++)
                           {
                              cout<<j<<endl;
                              j++;
                          }
                          //这里执行到10 j=10
                      });
    boost::asio::steady_timer timer2{pool.getIOCOntext(), std::chrono::seconds{4}};
    timer2.async_wait([&mtx,&j] (const boost::system::error_code &ec)
                      {
                          std::lock_guard<std::mutex> lock(mtx);
                          for(int i=0;i<10;i++)
                          {
                             cout<<j<<endl;
                             j++;
                         }
                      });
    pool.stop();
}

执行结果:

执行

发布了17 篇原创文章 · 获赞 3 · 访问量 416

猜你喜欢

转载自blog.csdn.net/qq_41172631/article/details/104931674
今日推荐