基于boost.asio的echo服务器2

26 篇文章 0 订阅
15 篇文章 0 订阅

在多处理器普及的现在,服务器程序会充分使用计算机多核的能力,比如nginx的master-worker多进程模式,那么今天我们就在1的基础上来通过多线程来使用多核。
进程和线程数不是越多越好,一般不要超过CPU核数的2倍。io_service是asio的事件循环,那么多线程就是几个io_service在各自的线程运行,这里我们使用io_service_pool类管理他们。

#define CPUS sysconf(_SC_NPROCESSORS_ONLN)

class io_service_pool : private boost::noncopyable
{
public:

    typedef boost::shared_ptr<io_service> io_service_ptr;
    typedef boost::shared_ptr<io_service::work> work_ptr;

    io_service_pool()
        : m_index(0)
    {
        std::cout << "--init--" << std::endl;
        init();
        std::cout << "--init--" << std::endl;
    }

    ~io_service_pool()
    {

    }

    void start()
    {
        std::cout << "--start--" << std::endl;
        if (!m_threads.size()) {
            for (std::vector<io_service_ptr>::iterator ite = m_io_services.begin();
                 ite != m_io_services.end(); ++ite) {
                m_threads.create_thread(boost::bind(&io_service::run, (*ite).get()));
            }
            std::cout << "--join--" << std::endl;
            m_threads.join_all();
            std::cout << "--join--" << std::endl;
        }
        std::cout << "--start--" << std::endl;
    }

    void stop()
    {
        for (std::vector<io_service_ptr>::iterator ite = m_io_services.begin();
             ite != m_io_services.end(); ++ite) {
            (*ite)->post(boost::bind(&io_service::stop, (*ite).get()));
        }
        m_works.clear();
    }

    io_service_ptr get()
    {
        if (m_index >= m_io_services.size()) {
            m_index = 0;
        }

        return m_io_services[m_index++];
    }

private:
    void init(int cpu = CPUS)
    {
        std::cout << "--cpu--:" << cpu << std::endl;
        for (int i = 0; i < cpu; ++i) {
            m_io_services.push_back(io_service_ptr(new io_service));
            m_works.push_back(work_ptr(new io_service::work(*m_io_services.back())));
        }
    }

    int m_index;

    std::vector<io_service_ptr> m_io_services;
    std::vector<work_ptr> m_works;
    boost::thread_group m_threads;


};

多线程方面我们使用boost::thread_group,其用来管理线程池很方便。
init函数根据本机的cpu核心数来初始化几个io_service,为了防止io_service在运行过程中因为如果没有需要等待的异步任务而退出,我们这个使用了io_service::work类,每个work类与和一个io_service绑定,有一个work就会改变io_service的中的一个标示+1,当其不为0的时候,io_service是不会退出循环的。

 void start()
    {
        std::cout << "--start--" << std::endl;
        if (!m_threads.size()) {
            for (std::vector<io_service_ptr>::iterator ite = m_io_services.begin();
                 ite != m_io_services.end(); ++ite) {
                m_threads.create_thread(boost::bind(&io_service::run, (*ite).get()));
            }
            std::cout << "--join--" << std::endl;
            m_threads.join_all();
            std::cout << "--join--" << std::endl;
        }
        std::cout << "--start--" << std::endl;
    }

start函数根据io_service来起线程,然后相应的线程中在执行run方法来跑事件循环,最后调用join_all使主线程等待所有线程结束。
我们使用轮询的策略来分配连接进来的客户连接。

  io_service_ptr get()
    {
        if (m_index >= m_io_services.size()) {
            m_index = 0;
        }

        return m_io_services[m_index++];
    }

echo2服务器类

class TestEchoServer2 : public boost::enable_shared_from_this<TestEchoServer2>
        , private boost::noncopyable
{
public:
    TestEchoServer2(io_service_pool &service_pool, int port)
        : m_io_service_pool(service_pool)
        , m_endpoint(ip::tcp::v4(), port)
        , m_acceptor(*(m_io_service_pool.get()), m_endpoint)
    {

    }

    ~TestEchoServer2()
    {

    }

    void start_accept()
    {
        m_connect.reset(new TestEchoConnection(*(m_io_service_pool.get()), m_connectionManager));
        m_acceptor.async_accept(m_connect->socket(), boost::bind(&TestEchoServer2::handle_accept, shared_from_this(), _1));
    }

private:

    void handle_accept(const boost::system::error_code &err)
    {
        if (!err) {
            m_connectionManager.push_back(m_connect);
            m_connect->start();

        }
        start_accept();
    }


private:
    io_service_pool& m_io_service_pool;
    ip::tcp::endpoint m_endpoint;
    ip::tcp::acceptor m_acceptor;
    MutexConnectionManager m_connectionManager;
    TestEchoConnection_ptr m_connect;

};

不同之处:

 void start_accept()
    {
        m_connect.reset(new TestEchoConnection(*(m_io_service_pool.get()), m_connectionManager));
        m_acceptor.async_accept(m_connect->socket(), boost::bind(&TestEchoServer2::handle_accept, shared_from_this(), _1));
    }

将新的connect绑定时是从线程池中获取的。

开始我没有修改connectionManager,还是使用的std::list,但是它不是线程安全的,我也没有加锁,然后跑跑就挂了。然后给他加上了锁。

template <typename T, typename T2>

class MutexList {
public:

    MutexList()
    {

    }

    ~MutexList()
    {

    }

    void remove(const T2& value)
    {
        m_mutex.lock();
        m_t2s.remove(value);
        m_mutex.unlock();
    }

    void push_back(const T2& value)
    {
        m_mutex.lock();
        m_t2s.push_back(value);
        m_mutex.unlock();
    }



private:
    std::list<T2> m_t2s;
    T m_mutex;

};

typedef MutexList<boost::mutex, TestEchoConnection_ptr> MutexConnectionManager;

那么对Connect也做了点修改,就是connectmanager的声明,操作的接口都是一样的,所以修改还是比较小。但是引入了锁竞争,而且那么对线程的优势在接入和断开这里就没了,比较好的解决办法就是没有线程使用自己各自的connectmanager。

使用siege测试

Transactions:               3799 hits
Availability:             100.00 %
Elapsed time:              19.81 secs
Data transferred:           3.20 MB
Response time:              0.00 secs
Transaction rate:         191.77 trans/sec
Throughput:             0.16 MB/sec
Concurrency:                0.26
Successful transactions:        3799
Failed transactions:               0
Longest transaction:            0.04
Shortest transaction:           0.00

性能还下降了,可能机器不一样有关,但是我感觉更多的是锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值