2014-10-21 20 views
6

Tôi đang bắt đầu một số coroutines với asio :: đẻ trứng, và tôi muốn đợi cho đến khi tất cả sau đó được hoàn thành và làm một số công việc khác sau đó. Làm thế nào nó có thể được thực hiện?Làm thế nào để chờ đợi để hoàn thành tất cả các tăng: asio của coroutines stackful?

Các dòng điều khiển được như sau:

asio::spawn (io, [] (asio::yield_context yield) { 
    ... 
    // starting few coroutines 
    asio::spawn (yield, [] (asio::yield_context yield2) { ... }); 
    asio::spawn (yield, [] (asio::yield_context yield2) { ... }); 
    asio::spawn (yield, [] (asio::yield_context yield2) { ... }); 
    asio::spawn (yield, [] (asio::yield_context yield2) { ... }); 

    // now I want to wait for all of them to finish before I do 
    // some other work? 
    ... 
}); 

io.run(); 

CẬP NHẬT

Dưới đây là các mẫu mã

#include <boost/asio.hpp> 
#include <boost/asio/spawn.hpp> 
#include <boost/asio/steady_timer.hpp> 
#include <chrono> 

#include <iostream> 
using namespace std; 

int main() 
{ 
    using namespace boost::asio; 

    io_service io; 

    spawn (io, [&] (yield_context yield) { 
    cout << "main coro starts\n"; 

    auto lambda = [&] (yield_context yield) 
     { 
     cout << "in lambda inside subcoroutine - starts\n"; 
     steady_timer t (io, std::chrono::seconds (1)); 
     t.async_wait (yield); 
     cout << "in lambda inside subcoroutine - finishes\n"; 
     }; 

    // starting few coroutines 
    spawn (yield, lambda); 
    spawn (yield, lambda); 

    // now I want to wait for all of them to finish before I do 
    // some other work? 
    // ??? 

    cout << "main coro finishes\n"; 
    }); 

    io.run(); 
} 

Và kết quả là:

// main coro starts 
// in lambda inside subcoroutine - starts 
// in lambda inside subcoroutine - starts 
// main coro finishes <---- 
// in lambda inside subcoroutine - finishes 
// in lambda inside subcoroutine - finishes 

Trong khi tôi đang mong đợi:

// main coro starts 
// in lambda inside subcoroutine - starts 
// in lambda inside subcoroutine - starts 
// in lambda inside subcoroutine - finishes 
// in lambda inside subcoroutine - finishes 
// main coro finishes 

(thấy nơi "kết thúc Coro chính" line)

+0

IIRC 'io.run();' chỉ thực hiện những gì bạn muốn ... – vines

+0

@vines - không, không phải vậy. [Mã Coliru] (http://coliru.stacked-crooked.com/a/e67cceb688156974) –

Trả lời

1

Tôi tìm thấy một ... loại workaround.

Tôi có thể sử dụng bộ hẹn giờ có thời lượng vô hạn và hủy bộ đếm thời gian từ chương trình con cuối cùng. Điều này sẽ đánh thức coroutine chính.

Coliru Example

#include <boost/asio.hpp> 
#include <boost/asio/spawn.hpp> 
#include <boost/asio/steady_timer.hpp> 

#include <iostream> 
using namespace std; 

int main() 
{ 
    using namespace boost::asio; 

    io_service io; 

    spawn (io, [&] (yield_context yield) { 
    cout << "main coro starts\n"; 


    steady_timer rendez_vous (io, steady_timer::clock_type::duration::max()); 
    /* volatile */ int counter = 2; 


    auto lambda = [&] (yield_context yield) 
     { 
     cout << "in lambda inside subcoroutine - starts\n"; 
     steady_timer t (io, boost::chrono::seconds (1)); 
     t.async_wait (yield); 
     cout << "in lambda inside subcoroutine - finishes\n"; 

     if (--counter == 0) 
      rendez_vous.cancel(); 
     }; 

    // starting few coroutines 
    spawn (yield, lambda); 
    spawn (yield, lambda); 

    // now I want to wait for all of them to finish before I do 
    // some other work? 
    // ??? 
    boost::system::error_code ignored_ec; 
    rendez_vous.async_wait (yield [ignored_ec]); 
    // ignore errors here by reason. 

    cout << "main coro finishes\n"; 
    }); 

    io.run(); 
} 

Thành thật mà nói tôi không thích giải pháp này, bởi vì nó lạm dụng "hẹn giờ" khái niệm và đối tượng và nó là một sự lãng phí có thể có của tài nguyên hệ thống.

+0

Tôi thích nó. Ngoại trừ việc lạm dụng 'biến động'. Nếu bạn muốn nó an toàn thread, sử dụng 'atomic_int'. Nếu không, chỉ cần để nó 'int' – sehe

+0

Đối với những gì nó có giá trị, tôi đã sử dụng một bộ đếm thời gian là tốt khi tôi đã có một nhu cầu tương tự. Nó cung cấp một giải pháp khá di động, và với một vài lớp cấp cao hơn trừu tượng việc thực hiện, nó cung cấp một giải pháp khá sạch sẽ. Tôi tin rằng 'counter' có thể là một 'int' bình thường, vì tất cả những coroutines này sẽ chạy trong cùng một' chuỗi' với các rào cản bộ nhớ thích hợp. –

0

Một lựa chọn tốt hơn là sử dụng sợi (boost.fiber tích hợp vào boost.asio). a boost :: fiber là lớp coroutine + scheduler + synchronization (API như std :: thread) và có thể được sử dụng trong ngữ cảnh boost.asio như coroutines.

+0

Tôi biết về boost.fiber và nó rất thú vị. Nhưng nó đã sẵn sàng để thử nhiệm vụ sản xuất chưa? Bạn nghĩ gì về nó? –

Các vấn đề liên quan