2015-05-31 25 views
5

Tôi không thể hình thành một hình ảnh tinh thần về cách thức dòng chảy kiểm soát xảy ra với đẻ trứng.Tăng cường :: asio :: spawn làm gì?

  1. Khi tôi gọi spawn(io_service, my_coroutine), nó thêm một handler mới vào hàng đợi io_service bọc lấy một cuộc gọi đến my_coroutine?

  2. Khi ở bên trong coroutine tôi gọi một hàm không đồng bộ qua nó yield_context của tôi, nó có treo hệ thống coroutine cho đến khi hoạt động không đồng bộ hoàn thành không?

    void my_coroutine(yield_context yield) 
    { 
        ... 
        async_foo(params ..., yield); 
        ... // control comes here only once the async_foo operation completes 
    }

Những gì tôi không hiểu là làm sao chúng ta tránh chờ đợi. Giả sử nếu my_coroutine phục vụ kết nối TCP, thì các phiên bản khác của my_coroutine được gọi như thế nào trong khi phiên bản cụ thể bị tạm ngưng, chờ async_foo hoàn tất?

Trả lời

17

Nói tóm lại:

  1. Khi spawn() được gọi, Boost.Asio thực hiện một số công việc cài đặt và sau đó sẽ sử dụng một strand-dispatch() một handler nội bộ mà tạo ra một coroutine sử dụng người sử dụng cung cấp chức năng như một điểm nhập cảnh. Trong các điều kiện nhất định, trình xử lý nội bộ có thể sẽ được gọi trong cuộc gọi tới spawn() và các lần khác nó sẽ được gửi đến số io_service để yêu cầu trì hoãn.
  2. coroutine bị đình chỉ cho đến khi hoạt động hoàn thành và trình xử lý hoàn thành được gọi, io_service bị hủy hoặc Boost.Asio phát hiện rằng coroutine đã bị treo mà không có cách nào để tiếp tục, tại điểm Boost.Asio sẽ hủy coroutine.

Như đã đề cập ở trên, khi spawn() được gọi, Boost.Asio thực hiện một số công việc cài đặt và sau đó sẽ sử dụng một strand-dispatch() một handler nội bộ mà tạo ra một coroutine sử dụng người sử dụng cung cấp chức năng như một điểm nhập cảnh. Khi đối tượng yield_context được truyền dưới dạng trình xử lý cho các hoạt động không đồng bộ, Boost.Asio sẽ sản lượng ngay sau khi bắt đầu thao tác không đồng bộ với trình xử lý hoàn tất sẽ sao chép kết quả và tiếp tục coroutine. Sợi được đề cập trước đây thuộc sở hữu của coroutine được sử dụng để đảm bảo hiệu suất xảy ra trước tiếp tục. Cho phép xem xét một ví dụ đơn giản demonstratingspawn():

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

boost::asio::io_service io_service; 

void other_work() 
{ 
    std::cout << "Other work" << std::endl; 
} 

void my_work(boost::asio::yield_context yield_context) 
{ 
    // Add more work to the io_service. 
    io_service.post(&other_work); 

    // Wait on a timer within the coroutine. 
    boost::asio::deadline_timer timer(io_service); 
    timer.expires_from_now(boost::posix_time::seconds(1)); 
    std::cout << "Start wait" << std::endl; 
    timer.async_wait(yield_context); 
    std::cout << "Woke up" << std::endl;  
} 

int main() 
{ 
    boost::asio::spawn(io_service, &my_work); 
    io_service.run(); 
} 

Các đầu ra ví dụ trên:

Start wait 
Other work 
Woke up 

Dưới đây là một nỗ lực để minh họa cho việc thực hiện các ví dụ. Paths trong | chỉ stack hoạt động, : chỉ ngăn xếp bị đình chỉ, và mũi tên được sử dụng để chỉ chuyển giao kiểm soát:

boost::asio::io_service io_service; 
boost::asio::spawn(io_service, &my_work); 
`-- dispatch a coroutine creator 
    into the io_service. 
io_service.run(); 
|-- invoke the coroutine creator 
| handler. 
| |-- create and jump into 
| | into coroutine   ----> my_work() 
: :        |-- post &other_work onto 
: :        | the io_service 
: :        |-- create timer 
: :        |-- set timer expiration 
: :        |-- cout << "Start wait" << endl; 
: :        |-- timer.async_wait(yield) 
: :        | |-- create error_code on stack 
: :        | |-- initiate async_wait operation, 
: :        | | passing in completion handler that 
: :        | | will resume the coroutine 
| `-- return     <---- | |-- yield 
|-- io_service has work (the   : : 
| &other_work and async_wait)  : : 
|-- invoke other_work()    : : 
| `-- cout << "Other work"   : : 
|  << endl;      : : 
|-- io_service still has work  : : 
| (the async_wait operation)  : : 
| ...async wait completes...  : : 
|-- invoke completion handler  : : 
| |-- copies error_code   : : 
| | provided by service   : : 
| | into the one on the   : : 
| | coroutine stack    : : 
| |-- resume     ----> | `-- return error code 
: :        |-- cout << "Woke up." << endl; 
: :        |-- exiting my_work block, timer is 
: :        | destroyed. 
| `-- return     <---- `-- coroutine done, yielding 
`-- no outstanding work in 
    io_service, return. 
+0

gì hành vi sao chép 'yield_context' vì nó được chuyển cho một coroutine làm gì? Nếu 'foo' chuyển' yield' thành 'bar',' bar' được chuyển tới 'baz', và' baz' gọi 'yield' - điều khiển có trực tiếp quay lại' foo' không? Khi cuộc gọi 'timer.async_wait'" sản lượng ", điều khiển có quay trở lại trình xử lý coroutine-creator, sau đó trả về? Khi thời gian sau đó hết hạn, kiểm soát quay lại 'async_wait' - sau đó trở về' my_work' như thế nào? – CppNoob

+0

@CppNoob Sự hỗ trợ hạng nhất của Boost.Asio cho Boost.Coroutine là một mặt tiền khá mỏng. Bạn đang cố gắng để hiểu làm thế nào Boost.Asio sử dụng Boost.Coroutine, hoặc làm thế nào Boost.Coroutine chính nó hoạt động? Sao chép 'yield_context' chỉ tạo một' yield_context' khác (không phải là coroutine). Khi 'timer.async_wait()' tạo ra coroutine, điều khiển nhảy tới ngăn bên trái ngay sau điểm bắt đầu coroutine. Khi trình xử lý hoàn thành của 'async_wait' được gọi, nó sẽ tiếp tục lại coroutine, khiến cho việc thực hiện nhảy tới ngay ngăn xếp ngay sau điểm mà nó đã mang lại. –

+0

Tôi đang cố gắng hiểu cách Boost Asio sử dụng coroutines - không phải từ góc thực hiện mà là cơ chế điều khiển luồng. Tôi nghĩ về yield_context như một ống dẫn để từ bỏ quyền kiểm soát đối với bối cảnh khác. Trong ví dụ này, hàm yield_context trong my_work đề cập đến bối cảnh trình xử lý coroutine-creator, và nó được sao chép như trình xử lý hoàn thành cho async_wait. Nhưng khi trình xử lý hoàn thành của async_wait thực hiện, điều khiển quay trở lại my_work, không phải trình xử lý người tạo ra coroutine (đã thoát ra lúc đó). Tôi rõ ràng không hiểu điều này, và tôi hy vọng tôi có thể mô tả những gì không rõ ràng. – CppNoob

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