【问题标题】:boost::asio::io_service::run in more than one threadboost::asio::io_service::在多个线程中运行
【发布时间】:2014-04-03 01:23:16
【问题描述】:

我试图使用 boost::asio::io_service 实现ActiveObject,但结果并不完全符合我的预期:

以下是我的代码:

#include    <boost/asio.hpp>
#include    <chrono>
#include    <boost/date_time/posix_time/posix_time.hpp>
#include    <memory>
#include    <thread>
#include    <string>
#include    <functional>
#include    <ctime>
#include    <chrono>

#define SIZE 10 

class ActiveObject
{
  public:
  ActiveObject()
  {
    executionThread_.reset( new std::thread(    [&]{  service_.run();  }  ) );
  }

    virtual ~ActiveObject()
    {
      // execute all unfinished work in case this object is leaving scope.
      service_.poll();
      service_.stop();
      executionThread_->join();
      std::cout << "active object thread exited" << std::endl;
    }

    void doSomething()
    {
      // post request the io_service to invoke someImpl method and return immediately
      service_.post([=]{ someImpl();});
    }

  protected:
    boost::asio::io_service service_;

  private:
    std::shared_ptr<std::thread> executionThread_;

    void someImpl() {
      std::chrono::milliseconds dura( 200 );
      std::this_thread::sleep_for( dura );
      std::cout << "poll thread id: " << std::this_thread::get_id() << std::endl;
    }

};

int main()
{
  std::cout << "main thread id: " << std::this_thread::get_id() << std::endl;

  ActiveObject obj;

  for(int i=0; i < SIZE; ++i) {
    obj.doSomething(); // call is nonblocking
  }

  std::cout <<  "main thread exited " << std::endl;
  return 0;
}

我想要的是在同一个线程上运行 boost::asio::io_service::run,但事实证明不是。从打印的日志来看,run() 也在主线程上运行。以下是打印的日志:

main thread id: 140070853244800
main thread exited 
poll thread id: 140070832256768
poll thread id: 140070853244800
poll thread id: 140070832256768
poll thread id: 140070853244800
poll thread id: 140070832256768
poll thread id: 140070853244800
poll thread id: 140070853244800
poll thread id: 140070832256768
poll thread id: 140070853244800
poll thread id: 140070832256768
active object thread exited

对此有任何想法吗?谢谢

【问题讨论】:

  • This 回答可能会提供有关如何在活动对象模式中实现某些元素的想法。

标签: c++ boost boost-asio


【解决方案1】:

至少在你做的地方

service_.poll();
service_.stop();

您正在积极地使服务在活动线程上运行。

为了缓解,你会说

service_.post([&] { service_.poll();});
service_.stop();

但是poll() 将是非常多余的。这似乎可以解决您的问题:

但是有一个大问题;

我们为什么还要打电话给stop()run() 完成所有工作后才完成,对吗?事实上,run() 可以在构建期间/之后立即完成。所有工作都将推迟到析构函数。

但是,如果run() 完成,则需要重置服务(),因此实际上可能不会运行任何工作(demo live on Coliru!!!)哎呀。这是一个令人讨厌的竞争条件。

为防止run()“过早”完成,请使用work 项目:Live On Coliru

#include <boost/asio.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <chrono>
#include <ctime>
#include <functional>
#include <memory>
#include <string>
#include <thread>

#define SIZE 10

class ActiveObject
{
public:
    ActiveObject()
        : service_(),
          work_(boost::asio::io_service::work(service_))
    {
        executionThread_.reset(new std::thread([&] { service_.run(); }));
    }

    virtual ~ActiveObject()
    {
        // execute all unfinished work in case this object is leaving scope.
        work_ = boost::none;
        executionThread_->join();
        std::cout << "active object thread exited" << std::endl;
    }

    void doSomething()
    {
        // post request the io_service to invoke someImpl method and return immediately
        service_.post([this] { someImpl();});
    }

protected:
    boost::asio::io_service service_;
    boost::optional<boost::asio::io_service::work> work_;

private:
    std::shared_ptr<std::thread> executionThread_;

    void someImpl()
    {
        std::chrono::milliseconds dura(200);
        std::this_thread::sleep_for(dura);
        std::cout << "poll thread id: " << std::this_thread::get_id() << std::endl;
    }

};

int main()
{
    std::cout << "main thread id: " << std::this_thread::get_id() << std::endl;

    ActiveObject obj;
    std::chrono::milliseconds dura(200);
    std::this_thread::sleep_for(dura);

    for(int i=0; i < SIZE; ++i)
    {
        obj.doSomething(); // call is nonblocking
    }

    std::this_thread::sleep_for(std::chrono::seconds(1));

    std::cout <<  "main thread exited " << std::endl;
}

输出:

main thread id: 140312603891520
poll thread id: 140312580617984
poll thread id: 140312580617984
poll thread id: 140312580617984
poll thread id: 140312580617984
main thread exited 
poll thread id: 140312580617984
poll thread id: 140312580617984
poll thread id: 140312580617984
poll thread id: 140312580617984
poll thread id: 140312580617984
poll thread id: 140312580617984
active object thread exited

【讨论】:

  • Boost.Asio 保证处理程序只会在调用 run()run_one()poll()poll_one() 的线程中运行。如果stop() 导致任务在调用线程中运行,那么这是一个错误。这是一个 coliru 演示预期行为。
  • @TannerSansbury 我现在无法复制它。我正在咨询的可能是一个陈旧的终端输出。我会修改文本,感谢您的更正(已完成,现在包括 coliru 链接)。
猜你喜欢
  • 2016-01-07
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多