2015-06-12 25 views
20

के साथ std :: async द्वारा लॉन्च किए गए थ्रेड के बारे में भ्रम मैं std::async फ़ंक्शन के बारे में थोड़ा उलझन में हूं।std :: async std :: async पैरामीटर

विनिर्देश कहता है: एसिंक्रोनस ऑपरेशन निष्पादित किया जा रहा है "जैसे कि निष्पादन के नए धागे में" (सी ++ 11 §30.6.8/11)।

अब, इसका क्या अर्थ है?

मेरी समझ में, कोड

std::future<double> fut = std::async(std::launch::async, pow2, num); 

एक नया धागा पर समारोह pow2 लांच और चर num भविष्य, जब समारोह किया जाता है में कुछ समय मूल्य से धागा करने के लिए गुजरती हैं, तो चाहिए, जगह परिणाम fut (जब तक कार्य pow2 में double pow2(double); जैसे हस्ताक्षर हैं)। लेकिन विनिर्देशन "जैसा है" कहता है, जो पूरी चीज को मेरे लिए थोड़ी दूर बनाता है।

सवाल यह है:

हमेशा इस मामले में शुरू की एक नई धागा है? मुझे उम्मीद है। मेरा मतलब है, पैरामीटर std::launch::async इस तरह से समझ में आता है कि मैं स्पष्ट रूप से बता रहा हूं कि मैं वास्तव में एक नया धागा बनाना चाहता हूं।

और कोड

std::future<double> fut = std::async(std::launch::deferred, pow2, num); 

आलसी मूल्यांकन संभव बनाना चाहिए, जहाँ मैं var = fut.get(); की तरह कुछ लिखने के लिए pow2 समारोह कॉल में देरी से। इस मामले में पैरामीटर std::launch::deferred, इसका मतलब यह होना चाहिए कि मैं स्पष्ट रूप से बता रहा हूं, मुझे कोई नया धागा नहीं चाहिए, मैं बस यह सुनिश्चित करना चाहता हूं कि फ़ंक्शन को इसके वापसी मूल्य की आवश्यकता होने पर कॉल किया जाए।

क्या मेरी धारणाएं सही हैं? यदि नहीं, तो कृपया समझाएं।

इसके अलावा, मुझे पता है कि डिफ़ॉल्ट रूप से समारोह के रूप में निम्नानुसार कहा जाता है:

std::future<double> fut = std::async(std::launch::deferred | std::launch::async, pow2, num); 

इस मामले में, मुझे बताया गया था कि एक नया धागा या शुरू किया जाएगा कि क्या नहीं कार्यान्वयन पर निर्भर करता है। दोबारा, इसका क्या अर्थ है?

+4

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

+0

@ टी.सी. या लागू (भारी) coroutine- स्थानीय चर। प्रत्येक थ्रेड को डिफ़ॉल्ट कोरआउटिन प्राप्त करें, और 'thread_local' कोरआउट स्थानीय है। 'Async' एक कोरआउटिन बना सकता है, कि कोरआउट को दूसरे थ्रेड में चलाया जा सकता है और चलाया जा सकता है। ओई, ओएस-प्रदत्त थ्रेड मॉडल के शीर्ष पर थ्रेडिंग (कोरआउट के साथ) अनुकरण करें? – Yakk

+1

मैंने ध्यान दिया 'std :: async' टूटा हुआ है, क्या यह सच है? –

उत्तर

23

std::async (<future> शीर्षलेख का हिस्सा) फ़ंक्शन टेम्पलेट का उपयोग (संभवतः) असीमित कार्य शुरू करने के लिए किया जाता है। यह std::future ऑब्जेक्ट देता है, जो अंततः std::async के पैरामीटर फ़ंक्शन का रिटर्न मान रखेगा।

जब मूल्य की आवश्यकता होती है, तो हम std::future उदाहरण पर() को कॉल करते हैं; यह भविष्य तक तैयार होने तक धागा को अवरुद्ध करता है और फिर मान देता है। कार्य को चलाने के तरीके को निर्दिष्ट करने के लिए std::launch::async या std::launch::deferred को std::async पर पहला पैरामीटर के रूप में निर्दिष्ट किया जा सकता है।

  1. std::launch::async इंगित करता है कि फ़ंक्शन कॉल अपने स्वयं के (नए) थ्रेड पर चलाना चाहिए। (उपयोगकर्ता @ टी.सी. की टिप्पणी को ध्यान में रखें)।
  2. std::launch::deferred इंगित करता है कि फ़ंक्शन कॉल को wait() या get() भविष्य में तब तक स्थगित कर दिया जाना चाहिए। ऐसा होने से पहले भविष्य के स्वामित्व को दूसरे धागे में स्थानांतरित किया जा सकता है।
  3. std::launch::async | std::launch::deferred इंगित करता है कि कार्यान्वयन चुन सकता है। यह डिफ़ॉल्ट विकल्प है (जब आप स्वयं को निर्दिष्ट नहीं करते हैं)। यह तुल्यकालिक रूप से चलाने का फैसला कर सकता है।

क्या इस मामले में हमेशा एक नया धागा लॉन्च किया गया है?

से, हम कह सकते हैं कि एक नया धागा हमेशा लॉन्च होता है।

क्या मेरी धारणाएं [std :: launch :: deferred] पर सही हैं?

से 2., हम कह सकते हैं कि आपकी धारणाएं सही हैं।

इसका क्या अर्थ है? [एक नया धागा के संबंध में शुरू की है या नहीं की जा रही क्रियान्वयन के आधार पर]

3. से, के रूप में std::launch::async | std::launch::deferred डिफ़ॉल्ट विकल्प है, इसका मतलब है कि टेम्पलेट समारोह std::async के कार्यान्वयन तय करेगा कि यह पैदा करेगा एक नया धागा या नहीं। ऐसा इसलिए है क्योंकि कुछ कार्यान्वयन शेड्यूलिंग के लिए जांच कर रहे हैं।

चेतावनी

निम्न अनुभाग आपके प्रश्न से संबंधित नहीं है, लेकिन मुझे लगता है कि यह महत्वपूर्ण है को ध्यान में रखना।

सी ++ मानक कहता है कि यदि std::future में एक असीमित फ़ंक्शन को कॉल के अनुरूप साझा स्थिति का अंतिम संदर्भ है, तो std :: भविष्य के विनाशक को अतुल्यकालिक चलने वाले फ़ंक्शन को समाप्त होने तक थ्रेड तक अवरुद्ध करना चाहिए। का एक उदाहरण std::async द्वारा लौटाया गया इस प्रकार इसके विनाशक में अवरुद्ध होगा।

void operation() 
{ 
    auto func = [] { std::this_thread::sleep_for(std::chrono::seconds(2)); }; 
    std::async(std::launch::async, func); 
    std::async(std::launch::async, func); 
    std::future<void> f{ std::async(std::launch::async, func) }; 
} 

यह भ्रामक कोड वे वास्तव में तुल्यकालिक हैं आपको लगता है कि std::async कॉल अतुल्यकालिक हैं कर सकते हैं। std::futurestd::async द्वारा लौटाए गए उदाहरण अस्थायी हैं और ब्लॉक करेंगे क्योंकि उनके विनाशक को सही कहा जाता है जब std::async लौटाता है क्योंकि उन्हें एक चर के लिए असाइन नहीं किया जाता है।

std::async पर पहला कॉल 2 सेकंड के लिए अवरुद्ध होगा, इसके बाद दूसरे कॉल से std::async पर 2 सेकंड अवरुद्ध हो जाएगा। हम सोच सकते हैं कि std::async पर अंतिम कॉल अवरुद्ध नहीं है, क्योंकि हम एक परिवर्तनीय में std::future इंस्टेंस को संग्रहीत करते हैं, लेकिन चूंकि यह एक स्थानीय चर है जो दायरे के अंत में नष्ट हो जाता है, यह वास्तव में अतिरिक्त 2 सेकंड के लिए अवरुद्ध होगा समारोह के दायरे के अंत में, जब स्थानीय परिवर्तनीय एफ नष्ट हो जाता है।

दूसरे शब्दों में, operation() फ़ंक्शन को कॉल करने से लगभग 6 सेकंड के लिए सिंक्रनाइज़ेशन पर जो भी थ्रेड कहा जाता है उसे अवरुद्ध कर देगा। ऐसी आवश्यकताएं C++ मानक के भविष्य के संस्करण में मौजूद नहीं हो सकती हैं।

सी ++ कार्रवाई में संगामिति: सूचना का

सूत्रों का कहना है मैं इन नोटों को संकलित करने के लिए प्रयोग किया जाता प्रैक्टिकल बहु सूत्रण, एंथनी विलियम्स

स्कॉट Meyers 'ब्लॉग पोस्ट: http://scottmeyers.blogspot.ca/2013/03/stdfutures-from-stdasync-arent-special.html

+0

बस स्पष्ट करने के लिए, यदि आप 'std :: async' की सादे कॉल को 'ऑटो t1 = std :: async (...) में बदलते हैं, तो आपके उदाहरण में, ब्लॉक समय केवल 2 सेकंड होगा, है ना? –

+0

@AdamHunyadi यदि आप कुल ब्लॉक समय का मतलब है - हाँ, क्योंकि तीन अलग-अलग धागे एक साथ सोएंगे। –

0

मैं भी से उलझन में था यह और विंडोज़ पर एक त्वरित परीक्षण चलाया जो दिखाता है कि एसिंक भविष्य ओएस थ्रेड पूल धागे पर चलाया जाएगा। एक साधारण एप्लिकेशन इसे प्रदर्शित कर सकता है, विजुअल स्टूडियो में तोड़ने से निष्पादित थ्रेड को "TppWorkerThread" भी दिखाया जाएगा।

#include <future> 
#include <thread> 
#include <iostream> 

using namespace std; 

int main() 
{ 
    cout << "main thread id " << this_thread::get_id() << endl; 

    future<int> f1 = async(launch::async, [](){ 
     cout << "future run on thread " << this_thread::get_id() << endl; 
     return 1; 
    }); 

    f1.get(); 

    future<int> f2 = async(launch::async, [](){ 
     cout << "future run on thread " << this_thread::get_id() << endl; 
     return 1; 
    }); 

    f2.get(); 

    future<int> f3 = async(launch::async, [](){ 
     cout << "future run on thread " << this_thread::get_id() << endl; 
     return 1; 
    }); 

    f3.get(); 

    cin.ignore(); 

    return 0; 
} 

के समान एक आउटपुट में परिणाम होगा:

main thread id 4164 
future run on thread 4188 
future run on thread 4188 
future run on thread 4188 
0

कि वास्तव में सच नहीं है। thread_local संग्रहीत मूल्य जोड़ें और आप देखेंगे, अलग धागे में वास्तव में std::async run f1 f2 f3 कार्य है, लेकिन साथ एक ही std::thread::id

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