2014-09-30 32 views
3

当使用Boost.Asio堆栈式协同程序时,如何“手动”产出以便另一个协同程序或异步操作有机会运行?例如,我需要发送给我从TCP套接字接收命令的响应之前执行长时间的计算:在Boost.Asio中产生Stackful Coroutine

asio::spawn(strand_, [this, self](asio::yield_context yield) 
{ 
    char data[256]; 
    while (socket_.is_open()) 
    { 
     size_t n = socket_.async_read_some(boost::asio::buffer(data), 
              yield); 

     if (startsWith(data, "computePi")) 
     { 
      while (!computationFinished) 
      { 
       computeSomeMore(); 
       yield; // WHAT SHOULD THIS LINE BE? 
      } 

      storeResultIn(data); 
      boost::asio::async_write(socket_, boost::asio::buffer(data, n), 
            yield); 
     } 
    } 
}); 

回答

4

这是简单的比你想象的:

iosvc.post(yield); 

会做的伎俩。

iosvc从@ sehe的示例代码借用)

+0

这确实看起来更干净。 – sehe 2014-10-05 18:06:23

4

你可以只调用poll_one()在io_service对象上。

全部工作示例:

#include <boost/asio.hpp> 
#include <boost/asio/spawn.hpp> 
#include <boost/algorithm/string/predicate.hpp> 
#include <boost/thread.hpp> 
#include <iostream> 

namespace asio = boost::asio; 
using boost::asio::ip::tcp; 
using std::begin; 
using std::end; 

bool computationFinished = false; 
void computeSomeMore() { 
    static int count = 0; 
    if (count++>10) 
    { 
     computationFinished = true; 
     std::cout << "Calculation finished\n"; 
    } else 
    { 
     std::cout << "Calculating...\n"; 
     boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); 
    } 
} 

template <typename T> void storeResultIn(T& a) { 
    std::fill(begin(a), end(a), '4'); 
} 

int main() 
{ 
    asio::io_service iosvc; 
    tcp::socket s(iosvc); 
    tcp::resolver r(iosvc); 

    tcp::acceptor a(iosvc, tcp::endpoint(tcp::v4(), 6767)); 

    a.accept(s); 
    { 
     asio::spawn(iosvc, [&iosvc,&s](asio::yield_context yield) 
     { 
      char data[256]; 
      while (s.is_open()) 
      { 
       size_t n = s.async_read_some(boost::asio::buffer(data), yield); 

       if (boost::algorithm::starts_with(data, "computePi")) 
       { 
        iosvc.post([]{std::cout << "I can still breath\n";}); // some demo work 
        iosvc.post([]{std::cout << "And be responsive\n";}); 

        while (!computationFinished) 
        { 
         computeSomeMore(); 
         iosvc.poll_one(); // this enables the demo work to be run 
        } 

        storeResultIn(data); 
        boost::asio::async_write(s, boost::asio::buffer(data, n), yield); 
       } else 
       { 
        std::cout << "Received unknown command '" << std::string(data, data+n) << "'\n"; 
       } 
      } 
     }); 
    } 

    iosvc.run(); 
    std::cout << "Bye bye\n"; 
} 

当发送 “computePi”,服务器打印:

Calculating... 
I can still breath 
Calculating... 
And be responsive 
Calculating... 
Calculating... 
Calculating... 
Calculating... 
Calculating... 
Calculating... 
Calculating... 
Calculating... 
Calculating... 
Calculation finished 
+0

新增工作示例 – sehe 2014-09-30 21:50:47

+0

我喜欢你怎么把我的'startsWith'和'storeResultIn'伪到实际工作的代码! – 2014-09-30 22:14:21

+3

这是[不可或缺的技能](http://kera.name/articles/2013/10/nobody-writes-testcases-any-more/)。我需要自己在可能的情况下测试我的答案。这是一项很棒的运动,而且很有趣。 – sehe 2014-09-30 22:21:09