2014-02-14 6 views
5

Kann ich Stackful Coroutine und boost::asio::steady_timer::async_wait in der folgenden Weise verwenden? Der Punkt ist, dass (beim Verständnis, nicht sicher) während des Wartens, lokale Variable timer ist nicht auf dem Stapel und damit unzugänglich. Kann der Rückruf normal fortgesetzt werden? (FYI, es funktioniert gut auf meinem Mac mit Klirren ++ 5.0.)Kann ich eine stackful-Coroutine als Wait-Handler eines steady_timer verwenden, der innerhalb der sehr stackful Coroutine definiert ist?

boost::asio::io_service io; 
void Work(boost::asio::yield_context yield) { 
    boost::asio::steady_timer timer(io); 

    timer.expires_from_now(std::chrono::seconds(5)); 
    timer.async_wait(yield); 

    cout << "Woke up." << endl; 
} 

int main() { 
    boost::asio::spawn(io, Work); 
    io.run(); 
    return 0; 
} 

Ich denke, es lohnt sich ein Vergleich zwischen dieser Frage: boost asio deadline_timer

+0

BTW, es ist „aufgewacht“ – marton78

Antwort

8

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. 
+0

Kann ein Thread mehrere Stapel (mehrere Stapelzeiger) haben? – updogliu

+0

@updogliu Die Ausführung kann zwischen mehreren Coroutinen innerhalb eines einzelnen Threads übertragen werden. Beispiele finden Sie in der [Motivation] (http://www.boost.org/doc/libs/1_55_0/libs/corutine/doc/html/coroutine/motivation.html) für Boost.Coroutine. –

+0

Ist das Abwickeln eines 'Coroutine'-Stapels (wegen' io_service' ist zerstört oder aus anderen Gründen) auch in den 'Strang' eingewickelt, in dem die' Coroutine' ausgeführt wird? – updogliu

2

ja - es sollte funktionieren. boost :: asio :: steady_timer timer (io) registriert den Timer auf dem io-service.

+0

Sie meinen Sie 'timer' nicht benötigt wird, mehr nach' async_wait' genannt wird? – updogliu