2012-12-18 64 views
2

我正在开发一个使用各种Boost函数的事件驱动的应用程序。我一直在计划将我的多线程架构基于ASIO的io_service对象,每个工作原子将由一个或多个线程组调度,每个线程组都调用run()来自boost asio的坏指针io_service get_service()

此引擎早期的一个“概念证明”版本使用单个io_service对象来派发许多不同的任务,包括截止时间定时器,网络I/O和发布的操作。由于这些早期版本有时可能会出现,这个早期版本并没有超过几个计划一次发送的事件。确信自己在正确的轨道上后,我重构了引擎的一部分以支持更精细的粒度和更高的可扩展性。但是这个新版本正在碰撞io_service对象中看似不好的指针。

我会尝试为我遇到的问题开发一个简化且可重复的测试用例。但我做之前,我想假设我的架构是基于确认...

单个io_service对象可以联网对象的多种间共享 - TCP UDP &做出决议,插座,定时器和其他任何野兽需要io_service对象引用。

我问的原因是,我一直无法在文档或在线讨论中找到明确说明的内容。另一个暗示我的io_service有问题的地方在于,我遇到了使用有效的端点和处理程序调用tcp :: socket的async_connect()下游某处的崩溃。执行async_connect()的最后一行调用this->get_service()。 stream_socket_service get_service()应该返回的指针最终为0x2,自从ENIAC以来,这并不是一个很好的指针值。

我的环境...

  • 我试着调试这个问题的Boost版本48至52

  • 我开发的OSX,并试图从不同的gcc 4.x的编译器版本4.2至4.7.3。

  • 在此腐败问题之前,我在会话中完成的异步操作包括一些定时器,udp解析和tcp解析。

  • 我正在执行async_connect()的套接字在调用之前在堆中被分配,并且在其构造函数中传递了io_service。

  • 我有一个io_service::work对象。

  • 我没有使用股(还)。

这是足够的信息,任何人的帮助,还是我需要提交一段可编译的代码?我也很喜欢io_service服务的入门书,其他SO读者也是如此。

更新#1:这是我遇到的问题的最小特征,我已经确认仍然崩溃。我使用最新的osx ML上的Boost 1.52.0,gcc 4.6.3构建它。

#include <stdlib.h> 
#include <string> 
#include <boost/bind.hpp> 
#include <boost/function.hpp> 
#include <boost/thread.hpp> 
#include <boost/thread/mutex.hpp> 
#include <boost/asio.hpp> 

namespace foo { 

namespace asio = boost::asio; 

class ios_threads : private boost::noncopyable 
{ 
public: 
    ios_threads(bool strt = false) 
    : work_(new asio::io_service::work(ios_)) 
    { 
     if (strt) 
      start(); 
    } 

    static asio::io_service &ios() 
    { 
     return ios_; 
    } 

    void start() 
    { 
     threads_.create_thread(boost::bind(&ios_threads::run, this)); 
    } 

    void wait() 
    { 
     threads_.join_all(); 
    } 

private: 
    void run() 
    { 
     while (true) { 
      try { 
       ios_.run(); 
      } 
      catch (std::exception &e) { 
       delete work_; 
       break; 
      } 
     } 

     printf("Shutting down.\n"); 
    } 

    static asio::io_service ios_; 

    asio::io_service::work *work_; 
    boost::thread_group threads_; 

}; 

asio::io_service ios_threads::ios_; 

struct op; 

typedef op * opPtr; 

struct op 
{ 
    typedef boost::recursive_mutex mutex_type; 

    op(op *del) 
    : delegate_(del) 
    { 
    } 

    virtual ~op() 
    { 
    } 

    bool start_async() 
    { 
     boost::unique_lock<mutex_type> lock(mutex_); 

     return start_it(); 
    } 

protected: 
    virtual bool start_it() 
    { 
     return false; 
    } 

    virtual void did_it(const boost::system::error_code& error) 
    { 
    } 

    void completion_handler(const boost::system::error_code& error) 
    { 
     boost::unique_lock<mutex_type> lock(mutex_); 

     did_it(error); 
    } 

    opPtr delegate_; 
    mutable mutex_type mutex_; 
}; 

struct interface_search : public op 
{ 
    typedef op super; 

    interface_search(op *del) 
    : super(del), 
     udp_resolver_(ios_threads::ios()) 
    { 
     it_ = NULL; 
    } 

    bool start_it() 
    { 
     try { 
      std::string hostname = boost::asio::ip::host_name(); 
      asio::ip::udp::resolver::query query(hostname, "", asio::ip::resolver_query_base::numeric_service | boost::asio::ip::resolver_query_base::passive); 
      udp_resolver_.async_resolve(query, boost::bind(&interface_search::udp_handler, this, asio::placeholders::error, asio::placeholders::iterator)); 
     } 
     catch (std::exception& e) { 
      printf("UDP resolve operation failed. Exception: %s", e.what()); 
     } 

     return super::start_it(); 
    } 

protected: 
    void udp_handler(const boost::system::error_code& error, asio::ip::udp::resolver::iterator it) 
    { 
     it_ = &it; 
     completion_handler(error); 
    } 

    void did_it(const boost::system::error_code& error) 
    { 
     if (error == asio::error::operation_aborted) 
      return; 

     op *del = delegate_; 

     if (del) 
      del->start_async(); 
    } 

    asio::ip::udp::resolver udp_resolver_; 
    asio::ip::udp::resolver::iterator *it_; 
}; 


struct google_connect : public op 
{ 
    typedef op super; 

    google_connect() 
    : super(NULL), 
     socket_(ios_threads::ios()) 
    { 
    } 

    void endpoint(asio::ip::tcp::endpoint &endpoint) 
    { 
     endpoint_ = endpoint; 
    } 

    bool start_it() 
    { 
     try { 
      // Crashes in the following call! 
      socket_.async_connect(endpoint_, boost::bind(&google_connect::connect_handler, this, asio::placeholders::error)); 
     } 
     catch (std::exception& e) { 
      printf(e.what()); 
     } 

     return super::start_it(); 
} 

    void connect_handler(const boost::system::error_code& error) 
    { 
     completion_handler(error); 
    } 

    void did_it(const boost::system::error_code& error) 
    { 
     if (error == asio::error::operation_aborted) 
      return; 

     boost::asio::ip::address addr = socket_.local_endpoint().address(); 

     printf(addr.to_string().c_str()); 
    } 

    asio::ip::tcp::socket socket_; 
    asio::ip::tcp::endpoint endpoint_; 
}; 

struct google_resolve : public op 
{ 
    typedef op super; 

    google_resolve() 
    : super(new google_connect()), 
     resolver_(ios_threads::ios()) 
    { 
     it_ = NULL; 
    } 

    bool start_it() 
    { 
     try { 
      asio::ip::tcp::resolver::query query(asio::ip::tcp::v4(), "google.com", "http"); 
      resolver_.async_resolve(query, boost::bind(&google_resolve::tcp_handler, this, asio::placeholders::error, asio::placeholders::iterator)); 
     } 
     catch (std::exception& e) { 
      printf(e.what()); 
     } 

     return super::start_it(); 
} 

protected: 
    void tcp_handler(const boost::system::error_code& error, asio::ip::tcp::resolver::iterator it) 
    { 
     it_ = &it; 
     completion_handler(error); 
    } 

    void did_it(const boost::system::error_code& error) 
    { 
     if (error == asio::error::operation_aborted) 
      return; 

     asio::ip::tcp::resolver::iterator last; 

     if (*it_ != last) { 
      google_connect *gc = static_cast< google_connect * >(delegate_); 

      if (gc) { 
       asio::ip::tcp::endpoint ep = **it_; 
       gc->endpoint(ep); 
       gc->start_async(); 

       super::did_it(error); 
      } 
     } 
    } 

    asio::ip::tcp::resolver resolver_; 
    asio::ip::tcp::resolver::iterator *it_; 
}; 

} // namespace foo 

int main(int argc, const char * argv[]) 
{ 
    try { 
     foo::ios_threads threads(false); 
     foo::opPtr ops_; 

     ops_ = new foo::interface_search(
      new foo::google_resolve() 
     ); 

     ops_->start_async(); 

     threads.start(); 
     threads.wait(); 
    } 
    catch (std::exception& e) { 
     printf(e.what()); 
    } 

    return 0; 
} 
+1

代码可以更好地解释将会发生什么 – PSIAlt

+1

您的假设是正确的。我想,你试图访问一个已经被销毁的对象。使用shared_from_this这个成语。 –

+0

如果您无法发布展示问题的代码,请使用类似[valgrind](http://valgrind.org)的工具来查找代码中的错误。 –

回答

2

为了别人的利益,我会自己回答这个问题。

我所描述的问题的原因是,从gcc 4.2转换到gcc 4.6.3并启用C++ 0x语言支持后,我需要链接到我构建编译器时构建的libstdC++库。运行时错误现在不再发生,因为我正在与适当的运行时库链接。

相关问题