提升 asio 行为 - 从多个线程调用 ios_service::run

Posted

技术标签:

【中文标题】提升 asio 行为 - 从多个线程调用 ios_service::run【英文标题】:boost asio behaviour - calling ios_service::run from multiple threads 【发布时间】:2014-07-20 00:03:04 【问题描述】:

我正在尝试使用 boost::asio 截止时间计时器来延迟函数调用,如下所示

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

class MyTest 
public:
    MyTest()
    :_invokeCount(0),
     _handleCount(0)
    

    void handler(int i)
    
        std::cout<<"\t\tHandled " <<i << std::endl;
        ++_handleCount;
    
    void RunIOService()
    
        std::cout<<"\tStarted :"<< _invokeCount<< std::endl;
        _ios.run();
        std::cout<<"\tFinished "<< _invokeCount << std::endl;
    
    void invokeTimer()
    
        std::cout<<"invoked " << ++_invokeCount << std::endl;

        boost::asio::deadline_timer t(_ios, boost::posix_time::milliseconds(5));
        t.async_wait(boost::bind(&MyTest::handler, this, _invokeCount));
        boost::thread th = boost::thread(boost::bind(&MyTest::RunIOService, this));
    
    void PrintCount()
    
        std::cout<<"Count = "<< _invokeCount << std::endl;
    
    void Wait()
    
        while (_invokeCount > _handleCount) 
            std::cout<<"X ";
            Sleep(1000);
        
    

private:
    int _invokeCount;
    int _handleCount;
    boost::asio::io_service _ios;
;

int main(int argc, char* argv[])

    MyTest test;
    for (int k=0; k<5; ++k) 
        test.invokeTimer();
        Sleep(40);
    
    test.Wait();
    test.PrintCount();

    return EXIT_SUCCESS;

这个应用程序的输出不是我预期的:-

invoked 1
    Started :1
        Handled 1
    Finished 1
invoked 2
    Started :2
    Finished 2
invoked 3
    Started :3
        Handled 2
    Finished 3
invoked 4
    Started :4
        Handled 3
    Finished 4
invoked 5
    Started :5
        Handled 4
    Finished 5
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 

我希望在 ios_service::run 返回之前调用每个处理程序,但从输出中看起来并非如此(在 Started:2 和 Finished:2 之间缺少输出)。此外,应用程序永远不会退出。即第 5 个处理程序永远不会被调用。

我错过了什么?

谢谢!

【问题讨论】:

【参考方案1】:

有几点:

    您可能不需要 5 个线程。为什么不创建一个线程并将事件触发到线程中运行的单个 ioservice 实例中 尝试在线程运行函数中使用io_service::work,以在处理所有请求时将io_service 保持在范围内。 等待结束后,停止io_service,加入线程并退出程序 在这里阅读io_service::work: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_service.html

【讨论】:

谢谢 - 在实际应用程序中,等效于 invokeTimer 的函数是基于事件的,所以我的想法是在事件到达时启动一个短期线程,而不是在整个生命周期内运行一个单独的线程应用程序(不确定 ios_service::work 的负载)。 Sammy - 你可以相信work 是高效的:它正是为此目的而设计的。线程池中的休眠线程没有运行时开销。 io_service 实际上是一个线程安全的任务队列,后台线程只是在等待工作到达时休眠。 (我会说使用带有“每个事件线程”模型的 Boost Asio 是本末倒置) (PS。重用相同队列/线程的开销(即使用io_service::work时)绝对小于启动一个新线程。Eeek)【参考方案2】:

我在每个 ios_service::run() 之后添加了 ios_service::reset() 并且它按预期工作。

【讨论】:

【参考方案3】:

boost::asio::ioservice::reset() 应该在后面的一组 run() 调用之前调用。 正如boost doc所说: 当由于 io_service 停止或用完而返回这些函数的先前调用时,必须在任何第二组或以后调用 run()、run_one()、poll() 或 poll_one() 函数之前调用此函数工作。此函数允许 io_service 重置任何内部状态,例如“停止”标志。

当对 run()、run_one()、poll() 或 poll_one() 函数有任何未完成的调用时,不得调用此函数。

【讨论】:

以上是关于提升 asio 行为 - 从多个线程调用 ios_service::run的主要内容,如果未能解决你的问题,请参考以下文章

从套接字和 STDIN 提升 Asio 多线程

提升ASIO IO_SERVICE实施?

提升::ASIO。确保仅在调用 async_receive(...) 后调用 io_service.run() ?

提升 Asio 单线程性能

如何在多个线程中安全地使用提升截止时间计时器?

C++ 提升 asio 多线程