Ja, es ist sicher, boost::asio::yield_context
an ein Objekt zu übergeben, das innerhalb derselben Coroutine eine automatische Speicherdauer hat.
Boost.Coroutine verwendet Boost.Context, um Kontextwechsel durchzuführen. Boost.Context bietet eine Möglichkeit, den aktuellen Ausführungspfad zu unterbrechen, den Stack zu erhalten (einschließlich lokaler Variablen wie Work()
timer
) und das Ausführungssteuerelement zu übertragen, sodass derselbe Thread mit einem anderen Stapel ausgeführt werden kann. Daher mit dem boost::asio::steady_timer
Objekt mit automatischer Speicherdauer wird seine Lebensdauer beendet, wenn entweder:
- Steuerung den Block durch
Work()
entweder über eine return
und erreichte Ende-Funktion oder eine Ausnahme Abwickeln des Stapels angegebenen austritt.
- Die zugehörige
io_service
ist zerstört. Interne Handler behalten das gemeinsame Eigentum an der Coroutine, und wenn die io_service
zerstört wird, werden alle zugehörigen Handler ebenfalls zerstört. Diese Zerstörung führt dazu, dass Boost.Coroutine den Stapel jedes Coroutines zum Abwickeln zwingt.
Wenn boost::asio::spawn()
aufgerufen wird, führt Boost.Asio einige Arbeit Einrichtung und anschließend wird einen internen dispatch()-Handler, der eine Koroutine unter Verwendung der Benutzerfunktion als Einstiegspunkt vorgesehen schaffen. Wenn das Objekt als yield_context
Handler asynchrone Operationen übergeben wird, ergibt Boost.Asio wird unmittelbar nach dem asynchronen Betrieb mit einem Abschluss-Handler, die Ergebnisse und Initiieren resume die Koroutine kopiert. Ein strand
Besitz der Coroutine wird verwendet, um zu garantieren, dass die Ausbeute vor resume auftritt. Hier ist ein Versuch, die Ausführung des Beispielcodes zu veranschaulichen:
boost::asio::io_service io_service;
boost::asio::spawn(io_service, &Work);
`-- dispatch a coroutine creator
into the io_service.
io_service.run();
|-- invoke the coroutine creator
| handler.
| |-- create and jump into
| | into coroutine ----> Work()
: : |-- timer created
: : |-- setting timer expiration
: : |-- 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 : :
| 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 << "Waked up." << endl;
: : |-- exiting Work() block, timer is
: : | destroyed.
| `-- return <---- `-- coroutine done, yielding
`-- no outstanding work in
io_service, return.
BTW, es ist „aufgewacht“ – marton78