2017-01-01 12 views
10

इस नवीनतम सी ++ टीएस: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4628.pdf के अनुसार, और सी # एसिंक/भाषा समर्थन का इंतजार करने के आधार पर, मुझे आश्चर्य है कि "निष्पादन संदर्भ" क्या है (शब्दावली सी #) सी ++ coroutines के?सी ++ 1z कोरआउटिन थ्रेडिंग संदर्भ और कोरआउट शेड्यूलिंग

विजुअल सी ++ 2017 आरसी में मेरा सरल परीक्षण कोड बताता है कि कोरआउट हमेशा थ्रेड पूल थ्रेड पर निष्पादित प्रतीत होता है, और एप्लिकेशन डेवलपर को थोड़ा नियंत्रण दिया जाता है जिस पर थ्रेडिंग संदर्भ को कोरआउट को निष्पादित किया जा सकता है - उदा। क्या कोई आवेदन सभी कोरआउट (संकलक उत्पन्न राज्य मशीन कोड के साथ) को मुख्य थ्रेड पर निष्पादित करने के लिए मजबूर कर सकता है, बिना किसी थ्रेड पूल थ्रेड के?

सी # में, सिंक्रनाइज़ेशन कॉन्टेक्स्ट "संदर्भ" निर्दिष्ट करने का एक तरीका है जहां सभी कोरआउट "हिस्सों" (कंपाइलर उत्पन्न राज्य मशीन कोड) पोस्ट और निष्पादित किए जाएंगे, जैसा कि इस पोस्ट में दिखाया गया है: https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/, जबकि वर्तमान कोरआउट कार्यान्वयन विज़ुअल सी ++ 2017 आरसी में हमेशा समवर्ती रनटाइम पर भरोसा होता है, जो डिफ़ॉल्ट रूप से जेनरेट पूल थ्रेड पर उत्पन्न राज्य मशीन कोड निष्पादित करता है। क्या सिंक्रनाइज़ेशन संदर्भ की एक समान अवधारणा है कि उपयोगकर्ता अनुप्रयोग कोरआउट निष्पादन को एक विशिष्ट धागे से बांधने के लिए उपयोग कर सकता है?

इसके अलावा, दृश्य सी ++ 2017 आरसी में लागू कोरआउट के वर्तमान डिफ़ॉल्ट "शेड्यूलर" व्यवहार क्या है? यानी 1) कैसे प्रतीक्षा की स्थिति बिल्कुल निर्दिष्ट है? और 2) जब प्रतीक्षा की स्थिति संतुष्ट होती है, तो निलंबित कोरआउट के "निचले आधे" का आह्वान कौन करता है?

सी # में कार्य शेड्यूलिंग के संबंध में मेरी (बेवकूफ) अटकलें यह है कि सी # कार्य कार्य निरंतरता द्वारा पूरी तरह से प्रतीक्षा की स्थिति को लागू करता है - एक प्रतीक्षा स्थिति को कार्यसमूह स्रोत के स्वामित्व वाले कार्य द्वारा संश्लेषित किया जाता है, और किसी भी कोड तर्क को प्रतीक्षा करने की आवश्यकता होती है इसके लिए निरंतरता के रूप में, इसलिए यदि प्रतीक्षा की स्थिति संतुष्ट है, उदाहरण के लिए यदि निम्न स्तर के नेटवर्क हैंडलर से एक पूर्ण संदेश प्राप्त होता है, तो यह कार्यकुशलता स्रोत .etValue करता है, जो अंतर्निहित कार्य को पूर्ण राज्य में परिवर्तित करता है, प्रभावी ढंग से जंजीर निरंतरता तर्क को निष्पादन शुरू करने की अनुमति देता है (कार्य को तैयार राज्य/सूची में डालकर पिछला बनाया गया राज्य) - सी ++ कोरआउटिन में, मैं अनुमान लगा रहा हूं कि std :: भविष्य और std :: वादा का उपयोग इसी तरह के तंत्र के रूप में किया जाएगा (std :: भविष्य कार्य है, जबकि std :: वादा कार्य पूर्णीकरण स्रोत है, और उपयोग आश्चर्यजनक रूप से भी समान है!) - सी ++ कोरआउटिन शेड्यूलर, यदि कोई है, तो व्यवहार करने के लिए कुछ समान तंत्र पर निर्भर करता है?

[संपादित करें]: कुछ और शोध करने के बाद, मैं एक बहुत ही सरल लेकिन बहुत शक्तिशाली अमूर्त कोड को कोड करने में सक्षम था जिसे एकल थ्रेडेड और सहकारी मल्टीटास्किंग का समर्थन करता है, और इसमें एक साधारण थ्रेड_लोकल आधारित शेड्यूलर है, जो कोरआउट को निष्पादित कर सकता है रूट कोरआउट शुरू किया गया है। कोड इस जिथब रेपो से पाया जा सकता है: https://github.com/llint/Awaitable

प्रतीक्षा योग्य इस तरह से संगत है कि यह नेस्टेड स्तरों पर सही आमंत्रण आदेश जारी रखता है, और इसमें आदिम उपज, समय प्रतीक्षा, और कहीं और से तैयार सेटिंग, और बहुत जटिल उपयोग पैटर्न इस से प्राप्त किया जा सकता है (जैसे अनंत लूपिंग कोरआउट जो कुछ घटनाओं के दौरान केवल जागृत हो जाते हैं), प्रोग्रामिंग मॉडल सी # कार्य आधारित async/निकटता पैटर्न का पालन करता है। कृपया अपनी प्रतिक्रिया देने के लिए स्वतंत्र महसूस करें।

+1

महान प्रश्न! सी # में कार्य शेड्यूलिंग के लिए [github] (https://github.com/dotnet/coreclr/tree/master/src/mscorlib/src/System/Threading/Tasks) पर सभी खुले हैं, कुछ अच्छी अंतर्दृष्टि प्रदान करते हैं। सी ++ के लिए, प्रस्तावों में से एक [n4286] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4286.pdf) (ड्राफ्ट में किए जाने से पहले) कवर डेमो कार्यान्वयन बूस्ट के वायदा पर, लेकिन ऐसा लगता है कि 'कौन' निरंतरता का आह्वान करता है वास्तव में निर्भर करता है –

+0

मुझे लगता है कि आपका प्रश्न थ्रेड/संदर्भ पर समान रूप से लागू है जहां [भविष्य :: तब] (http://en.cppreference.com/w/ सीपीपी/प्रयोगात्मक/भविष्य/फिर) कहा जाएगा, यानी अपरिभाषित ¯ \ _ (ツ) _/¯ –

+1

टिप्पणियों के लिए धन्यवाद। "कौन" निरंतरता का आह्वान करता है, हालांकि, मैं अनुमान लगाता हूं कि कुछ प्रस्तावित मानक शब्द या सुविधाएं होनी चाहिए जो कस्टम सिंगल थ्रेड कोरआउट शेड्यूलर के कार्यान्वयन का समर्थन करेंगी - उदा।यदि सब कुछ मुख्य धागे पर निष्पादित किया जा रहा है, तो मुख्य शेड्यूलर लूप (या टिक) होना चाहिए जिसे मुख्य थ्रेड पर बुलाया जा सकता है कि सभी निर्धारित "कार्य हिस्सों" को निष्पादित किया जाएगा - या "मुख्य" धागा कोई भी धागा हो सकता है जिसे मैं अधिक अनियंत्रित थ्रेड पूल धागे के खिलाफ चुनता हूं। – Dejavu

उत्तर

9

विपरीत!

सी ++ कोरआउटिन नियंत्रण के बारे में है। यहां मुख्य बिंदु
void await_suspend(std::experimental::coroutine_handle<> handle) फ़ंक्शन है।

evey co_await प्रतीक्षा करने योग्य प्रकार की अपेक्षा करता है।- कार्यक्रम coroutine के निष्पादन को रोकने चाहिए

  1. bool await_ready(): संक्षेप में, awaitable प्रकार एक प्रकार है जो इन तीन कार्यों प्रदान करना है?
  2. void await_suspend(handle) - कार्यक्रम आपको उस कोरआउट फ्रेम के लिए निरंतर संदर्भ पास करता है। यदि आप हैंडल को सक्रिय करते हैं (उदाहरण के लिए, operator() पर कॉल करके जो हैंडल प्रदान करता है - वर्तमान धागा तुरंत कोरआउट को फिर से शुरू करता है)।
  3. T await_resume() - उस धागे को बताता है जो कोरआउटिन को फिर से शुरू करता है जब कोरआउटिन को फिर से शुरू किया जाता है और co_await से वापस क्या किया जाता है।

इसलिए जब आप awaitable प्रकार पर co_await फोन, कार्यक्रम awaitable पूछता है कि coroutine निलंबित किया जाना चाहिए (यदि await_ready रिटर्न गलत) और यदि ऐसा है तो - आप एक coroutine संभाल जिसमें आप क्या कर सकते हैं जो कुछ भी आप की तरह मिलता है।

उदाहरण के लिए, आप कोरआउट हैंडल को थ्रेड-पूल में पास कर सकते हैं। इस मामले में एक थ्रेड-पूल धागा कोरआउटिन फिर से शुरू करेगा।

आप कोरआउटिन हैंडल को सरल std::thread पर पास कर सकते हैं - आपके अपने थ्रेड को कोरआउटिन फिर से शुरू कर देगा।

आप कोरोटिन हैंडल OVERLAPPED की व्युत्पन्न कक्षा में संलग्न कर सकते हैं और जब एसिंक्रोनस आईओ खत्म होता है तो कोरआउटिन फिर से शुरू कर सकते हैं।

जैसा कि आप देख सकते हैं - आप नियंत्रित कर सकते हैं कि कोरआउटिन को निलंबित कर दिया गया है और फिर से शुरू होता है - await_suspend में पारित कोरआउटिन हैंडल का प्रबंधन करके। कोई "डिफ़ॉल्ट शेड्यूलर" नहीं है - आप कैसे कार्यान्वित करते हैं आप प्रतीक्षा करने योग्य प्रकार तय करेंगे कि कोरआउट को शेड्यूल किया गया है।

तो, वीसी ++ में क्या होता है? दुर्भाग्य से, std::future में अभी भी then फ़ंक्शन नहीं है, इसलिए आप std::future पर कोरआउट हैंडल पास नहीं कर सकते हैं। यदि आप std::future पर इंतजार कर रहे हैं - कार्यक्रम सिर्फ एक नया धागा खुल जाएगा।

template<class _Ty> 
    void await_suspend(future<_Ty>& _Fut, 
     experimental::coroutine_handle<> _ResumeCb) 
    { // change to .then when future gets .then 
    thread _WaitingThread([&_Fut, _ResumeCb]{ 
     _Fut.wait(); 
     _ResumeCb(); 
    }); 
    _WaitingThread.detach(); 
    } 

तो क्यों आप एक Win32 ThreadPool धागा अगर coroutines एक नियमित std::thread में शुरू कर रहे हैं देखा था: future हैडर द्वारा दिए गए स्रोत कोड को देखो? ऐसा इसलिए है क्योंकि यह कोरआउट नहीं था। std::async दृश्यों के पीछे concurrency::create_task पर कॉल करें। एक concurrency::task डिफ़ॉल्ट रूप से Win32 थ्रेडपूल के तहत लॉन्च किया गया है। आखिरकार, std::async का पूरा उद्देश्य किसी अन्य थ्रेड में कॉल करने योग्य लॉन्च करना है।

+0

बढ़िया! यह जवाब coroutines के थ्रेडिंग/निष्पादन संदर्भ के रहस्य को स्पष्ट करने के लिए प्रतीत होता है। ऐसा लगता है कि भविष्य का समर्थन करने के लिए। फिर (उर्फ कार्य निरंतरता), अभी भी एक कार्य शेड्यूलर की आवश्यकता प्रतीत होती है कि निरंतरता केवल चलाने के लिए निर्धारित की जाएगी (शायद विशिष्ट शेड्यूलर के आधार पर उसी धागे संदर्भ पर कार्यान्वयन) जब वर्तमान कार्य/भविष्य पूरा हो जाता है - वीसी ++ दृष्टिकोण कार्य शेड्यूलर का उपयोग करके घूमता है क्योंकि यह एक अलग थ्रेड पर अवरुद्ध प्रतीक्षा पर निर्भर करता है और फिर उस धागे पर कोरआउटिन को फिर से शुरू करता है। – Dejavu

+0

'थ्रेड को बताता है जो कोरआउटिन को फिर से शुरू करता है और कोर_वाइट से वापस लौटने पर क्या करना है।' मुझे यकीन नहीं है कि यह पूरी तरह से सटीक है, फिर भी "निलंबन-फिर-बिंदु" और उसके ऑपरेटर()() में पुन: शुरू होगा coroutine_handle का कहना है कि "क्या करना है"। 'await_resume' एक अंतिम मूल्य प्राप्त करने के लिए सिर्फ एक हुक है और शायद कुछ मामलों में खाली छोड़ दिया गया है –

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