2011-05-18 84 views
1

我有一个使用io_service和多个线程的程序。在Ubuntu 11.04上升压:: asio :: strand断了(boost_all_dev 1.42)

它实例化一些套接字对象。这些对象每个都有一个同步链。所有对async_read(),async_write()和类似函数的调用都会经过strand_.wrap(boost :: bind(...))。每个对象还具有被初始化为0。

内这些功能之一(接通数据接收回调)一个int interlock_变量,i执行以下操作:

Class::startRead(...) 
{ 
... 
    boost::asio::async_read(socket_, boost::asio::buffer(ptr, 16384), boost::asio::transfer_at_least(1), 
     strand_.wrap(boost::bind(&EagerConnection::on_read, this, placeholders::error, placeholders::bytes_transferred))); 
} 

Class::on_read(...) 
{ 
... 
    startRead(); 
    assert(0 == __sync_fetch_and_add(&interlock_, 1)); 
    onData_(); 
    assert(1 == __sync_fetch_and_add(&interlock_, -1)); 
} 

因为一切是通过同步那首先声称绝不应该开火的那股。但是,它确实发射了!当我检查GDB中的值时,interlock_的结束值是2,这意味着两个单独的on_read()调用同时处于活动状态。

这是否意味着boost :: asio :: strand被破坏? (我已经检查过在完成函数中没有任何重新进入 - onData_信号处理程序不会重新调用on_data())。

“early”startRead是否可以导致立即重新进入? (无论async_x和链的语义似乎表明它不能)

如果你真的想看到的类的完整的上下文,它可以作为一个要点:https://gist.github.com/979212

回答

0

我发现了一些小的(?)问题:

  • 小:中interlock_strand_初始化顺序切换。通过声明interlock__after_这个strand_成员来修复它;

  • readIn函数不返回任何值(未初始化的数据)。您可能打算返回n


好消息:

  • 用Valgrind的运行打开了明确。
  • 与helgrind运行明确(但:我不使用线程在我最小的例子,我猜;不知道boost::asioboost::signals内部)。
0

我想重现的东西,但我的安装无法提出这样做​​时断言。

我上涨了下面的代码片段在主旨的结尾:

int split(std::string const &src, char ch, std::string &oLeft, std::string &oRight) 
{ 
    std::size_t pos = src.find(ch); 
    if (pos == std::string::npos) 
    { 
     oLeft = src; 
     oRight.clear(); 
     return 1; 
    } else 
    { 
     oLeft = src.substr(0, pos); 
     oRight = src.substr(pos+1); 
     return 2; 
    } 
} 

namespace { 

    boost::asio::io_service svc; 
    EagerConnection c(svc); 

    void onconnect() 
    { 
     std::cout << "ONCONNECT" << std::endl; 
     const char data[] = "GET/HTTP/1.0\r\n\r\n"; 
     c.writeOut(data, sizeof(data)); 
    } 

    void ondata() 
    { 
     std::cout << "ONDATA" << std::endl; 
     std::ostringstream oss; 
     char buf[1024]; 
     int read; 
     while ((read = c.readIn(buf, 1024))) 
      oss.write(buf, read); 
     std::cout << "response: " << oss.str() << std::endl; 
    } 

    void ondisconnect() 
    { 
     std::cout << "ON__DIS__CONNECT" << std::endl; 
    } 

} 

int main(int argc, char* argv[]) 
{ 
    if (argc>1 && argv[1]) 
    { 
     c.onConnect_.connect(&onconnect); 
     c.onData_.connect(&ondata); 
     c.onDisconnect_.connect(&ondisconnect); 


     c.open(argv[1]); 
     svc.run(); 
    } 

    return 0; 
} 

正如你所看到的,我真正想要做的SimplestThingThatCouldPossiblyWork。我的连接/重新连接正常工作(包括增加的退避时间)。

strand: strand.cpp 
    g++ -Wall -Werror -o [email protected] $^ -g -O0 -lboost_system -lboost_thread -lboost_signals -lpthread 

编译这一点,并

./strand 127.0.0.1:6767 

我有一个响应脚本坐在那里什么(基本)

netcat -l -p 6767 -e rev 

其他有一点要注意调用它:写缓冲区似乎永远不会被发送/清除直到我中断了strand测试仪(客户端)。无论我做多大data ...这可能是由于我错过了一步?

编辑

测试相同上

  • ubuntu的猫鼬,GCC 4.4.5,升压1.42.0
  • Debian的SID,GCC 4.5.2-8,升压1.46.1
+0

感谢您的企图!这可能是因为我使用的安装(10.04 LTS)有一些bug在更高版本中修复。请注意,我几乎坚持这个版本,但。 – 2011-06-21 04:56:14