Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何正确关闭使用asio进行事件队列的类的实例_C++_Multithreading_Boost_Boost Asio_Shared Ptr - Fatal编程技术网

C++ 如何正确关闭使用asio进行事件队列的类的实例

C++ 如何正确关闭使用asio进行事件队列的类的实例,c++,multithreading,boost,boost-asio,shared-ptr,C++,Multithreading,Boost,Boost Asio,Shared Ptr,在我的项目中,我广泛使用boost asio,以便能够使用io_service.post()和strand.post()/dispatch()将非统一事件统一排队到应用程序中的模块 在main()中,这些模块被创建并保存在共享_ptr中,直到程序退出并被删除: simplified main: { [some initialization] boost::asio::io_service service; [create pool of worker threads that d

在我的项目中,我广泛使用boost asio,以便能够使用io_service.post()和strand.post()/dispatch()将非统一事件统一排队到应用程序中的模块

在main()中,这些模块被创建并保存在共享_ptr中,直到程序退出并被删除:

simplified main:
{
  [some initialization]

  boost::asio::io_service service;

  [create pool of worker threads that drive the io_service]

  {
    boost::shared_ptr<manager_a> a(new manager_a(service, foo));
    boost::shared_ptr<manager_b> b(new manager_b(service, bar, blah));
    ...

    [wait for signal to shutdown (SIGINT (release), cin.getc() (debug), or similar)]
  }

  [some shutdown (join thread pool)]
}
在析构函数中:

manager_a::~manager_a()
{
  m_module->unregister(this);
}
管理器通过通过链发布调用来实现回调接口:

void manager_a::on_module_cb(module_message m)
{
  // unsafe to do work here, because the callback is from an alien thread
  m_strand.dispatch(boost::bind(&manager_a::handle_module_message, shared_from_this(), m));
}
void manager_a::handle_module_message(module_message m)
{
  // safe to do work here, as we're serialized by the strand
}
现在我面临的困境是:

如果“module”在构造函数中的
寄存器(this)
之后立即调用回调,则main中的shared\u ptr尚未接管实例,回调函数中的
shared\u from\u this()
抛出异常。析构函数也存在同样的问题-共享的\u ptr已确定它具有最后一个引用,并且当调用析构函数时,如果在
取消注册(this)
之前调用回调,则从\u this()抛出
共享的\u

之所以需要
shared\u from\u this()
,是因为排队函数调用存储在io\u服务中,该服务持有指向管理器实例的指针,并且独立于管理器的生存期。我可以给“模块”一个原始的
this
,因为我可以在manager\u a被销毁之前注销它,但是对于io\u服务中的排队函数调用,情况并非如此,因此需要一个
shared\u from\u this()
来保持实例的活动状态,只要发布了一些消息。您也不能取消这些操作,也不能阻止在析构函数中等待,直到所有挂起的帖子都被传递。不幸的是,就像现在这样,我甚至不能阻止新帖子在关键的构造函数/析构函数阶段排队

一些想法:

  • 写入启动/停止函数,并在那里注册/取消注册。例如,创建如下工厂功能:

    boost::shared_ptr<manager_a> manager_a::create(io_service& s, module *m)
    {
      boost::shared_ptr<manager_a> p(new manager_a(s, m));
      p->start();
      return p;
    }
    
    boost::共享ptr管理器\u a::创建(io\u服务与s,模块*m)
    {
    boost::shared_ptr p(新经理a(s,m));
    p->start();
    返回p;
    }
    
    这只适用于创造,而不适用于毁灭。为共享的\u ptr提供一个自定义的deleter(在delete之前调用stop())没有帮助,因为无论如何已经太晚了

  • 让main()调用start()和stop(),但我不知道main()如何以异常安全的方式为stop()调用执行此操作,也就是说,即使稍后有代码抛出,也要确保调用stop()。让另一个RAII类仅仅调用stop()似乎很尴尬

  • 只需将strand.dispatch()调用包装为try/catch并忽略异常。这表示正在进行销毁(或构建尚未完成),因此忽略回调。这让人觉得有点刻薄,我不想那样做。如果我可以从这个
  • 基类访问
    enable\u shared\u中嵌入的弱ptr,我可以调用非抛出的
    lock()
    并检查返回值是否有效。但是,从共享的__这并没有给你访问权限,而且它仍然看起来很黑客。。。此外,在构造过程中错过回调也没有帮助,即使我可以解决这个问题

  • 让manager_a拥有自己的io_服务和驱动它的线程。然后,在析构函数中,我可以停止服务并加入线程,确保io_服务中没有挂起的帖子。也不再需要从此()共享的
    shared\u,也不需要串。我想这是可行的,但这样一来,在main()中为所有管理器提供一个线程池就变得毫无意义了,而且我的应用程序中的线程会比看起来合理的多得多。其他模块中已经有足够多的线程不使用asio\U服务


  • 您的问题并不清楚,但如果所有管理器对象都是在启动时创建的,并在退出时删除,那么问题的解决方案是在启动IO线程之前创建管理器,并在删除管理器之前停止IO线程。这将阻止您在不需要回拨时收到回拨。

    您可以使用
    模块中的互斥来停止对它的任何调用,直到注册完成。除此之外,选项1在我看来很好。你使用它有什么问题?为什么使用定制的删除器不起作用?你的意思是,
    寄存器(this)
    调用应该是原子的?已经是了,这不是问题所在。问题是,一旦注册完成,
    模块
    就可以自由地回拨,而且它确实可以。自定义删除程序不起作用,因为智能指针会在调用析构函数或自定义删除程序之前释放引用。好主意。不幸的是,如果管理者需要该服务进行清理,例如向其子工作人员(连接实例)发布终止请求,那么这也不会起作用。。。无论如何,我会接受这个答案,因为考虑到后果,它应该是有效的。到目前为止,我的问题中的想法是4。谢谢
    boost::shared_ptr<manager_a> manager_a::create(io_service& s, module *m)
    {
      boost::shared_ptr<manager_a> p(new manager_a(s, m));
      p->start();
      return p;
    }