2015-05-31 6 views
5

मैं एक मानसिक तस्वीर बनाने में असमर्थ हूं कि स्पॉन के साथ नियंत्रण प्रवाह कैसा होता है।बढ़ावा देता है :: asio :: spawn क्या करता है?

  1. जब मैं फोन spawn(io_service, my_coroutine), यह io_service कतार कि my_coroutine के लिए एक कॉल लपेटता के लिए एक नया हैंडलर जोड़ने करता है?

  2. कोरआउटिन के अंदर जब मैं एसिंक फ़ंक्शन को अपने yield_context से गुजरता हूं, तो क्या यह एसिंक ऑपरेशन पूरा होने तक कोरआउटिन को निलंबित करता है?

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

क्या मुझे समझ नहीं आता कि कैसे हम इंतजार से बचने के है। कहो अगर my_coroutine TCP कनेक्शन कार्य करता है, कैसे my_coroutine के अन्य उदाहरण लागू कर रहे हैं, जबकि विशेष उदाहरण पर निलंबित कर दिया है, async_foo को पूरा करने के लिए इंतज़ार कर रहे?

उत्तर

17

संक्षेप में:

  1. जब spawn() शुरू हो जाती है, Boost.Asio कुछ सेटअप काम करता है और फिर एक stranddispatch() एक आंतरिक हैंडलर है कि एक coroutine एक प्रवेश बिंदु के रूप में प्रदान की जाती समारोह उपयोगकर्ता का उपयोग कर बनाता है का उपयोग करेगा। कुछ स्थितियों के तहत, आंतरिक हैंडलर को कॉल के भीतर spawn() पर बुलाया जा सकता है, और अन्य बार इसे स्थगित आमंत्रण के लिए io_service पर पोस्ट किया जाएगा।
  2. कोरआउट को तब तक निलंबित कर दिया जाता है जब तक कि ऑपरेशन पूरा नहीं हो जाता है और पूरा होने वाला हैंडलर लागू होता है, io_service नष्ट हो जाता है, या बूस्ट। एसीओ पता लगाता है कि कोरआउट को इसे फिर से शुरू करने के किसी भी तरीके से निलंबित कर दिया गया है, जिस बिंदु पर बूस्ट.एसीओ नष्ट हो जाएगा coroutine।

ऊपर उल्लेख किया है, जब spawn() शुरू हो जाती है, Boost.Asio कुछ सेटअप काम करता है और फिर एक stranddispatch() एक आंतरिक हैंडलर है कि एक coroutine एक प्रवेश बिंदु के रूप में प्रदान की जाती समारोह उपयोगकर्ता का उपयोग कर बनाता है का उपयोग करेगा। जब yield_context ऑब्जेक्ट को एक हैंडलर के रूप में एसिंक्रोनस ऑपरेशंस के रूप में पास किया जाता है, तो बूस्ट.एएसियो उपज उपरोक्त हैडलर के साथ एसिंक्रोनस ऑपरेशन शुरू करने के तुरंत बाद परिणाम देगा और कोरआउटिन फिर से शुरू करेगा। जैसा कि पहले उल्लेख किनारा coroutine के स्वामित्व में है से पहले फिर से शुरूउपज होता है गारंटी करने के लिए प्रयोग किया जाता है।

#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(); 
} 

ऊपर के उदाहरण आउटपुट: एक साधारण उदाहरण demonstratingspawn() पर विचार देता है

Start wait 
Other work 
Woke up 

यहाँ उदाहरण के निष्पादन के उदाहरण देकर स्पष्ट करने का प्रयास है। | में पथ से संकेत मिलता है सक्रिय ढेर, : इंगित करता निलंबित ढेर, और तीर नियंत्रण के हस्तांतरण इंगित करने के लिए उपयोग किया जाता है:

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

क्या कॉपी करने का कार्य करता है 'yield_context' के रूप में यह एक coroutine में भेजा जाता है क्या ज़रूरत है? यदि 'foo'' bar' को 'उपज' पास करता है, 'बार '' बाज़' को पास किया जाता है, और 'बाज़' कॉल 'उपज' - क्या नियंत्रण सीधे 'foo' पर जाता है? जब 'timer.async_wait' कॉल" उपज "करता है, तो क्या नियंत्रण कोरआउट-निर्माता हैंडलर पर वापस जाता है, जो तब वापस आता है? जब समय बाद समाप्त हो जाता है, तो नियंत्रण 'async_wait' पर वापस कैसे जाता है - जो तब' my_work' पर वापस आता है? – CppNoob

+0

@CppNoob Boost.Aostio Boost.Coroutine के लिए प्रथम श्रेणी का समर्थन एक काफी पतला मुखौटा है। क्या आप यह समझने की कोशिश कर रहे हैं कि Boost.Asio Boost.Coroutine का उपयोग करता है, या कैसे बूस्ट। कोरआउट स्वयं काम करता है? 'Yield_context' की प्रतिलिपि बनाना सिर्फ एक अन्य' yield_context' बनाता है (कोरआउट नहीं)। जब 'timer.async_wait()' coroutine उत्पन्न करता है, उस बिंदु के तुरंत बाद बाएं स्टैक पर नियंत्रण कूदता है जिस पर कोरआउटिन शुरू होता है। जब 'async_wait' के पूर्ण होने वाले हैंडलर को बुलाया जाता है, तो यह कोरआउटिन को फिर से शुरू करता है, जिससे उस बिंदु के तुरंत बाद निष्पादन दाहिने ढेर तक पहुंच जाता है। –

+0

मैं समझने की कोशिश कर रहा हूं कि कैसे बूस्ट एएसओ कोरआउटिन का उपयोग करता है - कार्यान्वयन कोण से नहीं बल्कि नियंत्रण प्रवाह तंत्र के रूप में। मैं yield_context को किसी अन्य संदर्भ में नियंत्रण छोड़ने के लिए एक संवहनी के रूप में सोचता हूं। इस उदाहरण में, my_work में yield_context कोरआउट-निर्माता हैंडलर संदर्भ को संदर्भित करता है, और इसे async_wait के लिए पूर्णता हैंडलर के रूप में कॉपी किया गया है। लेकिन जब async_wait के समापन हैंडलर निष्पादित होते हैं, तो नियंत्रण मेरे_वर्क पर वापस जाता है, न कि कोरआउटिन-निर्माता हैंडलर (जो तब तक निकलता है)। मैं स्पष्ट रूप से इसे समझ नहीं पा रहा हूं, और मुझे उम्मीद है कि मैं स्पष्ट कर सकता हूं कि क्या स्पष्ट नहीं है। – CppNoob

संबंधित मुद्दे