2012-04-17 18 views
11

मैं vc2011 का उपयोग कर रहा हूं और यह std :: async (std :: launch :: async, ...) को थोड़ा सा गड़बड़ कर देता है (कभी-कभी यह नए धागे को नहीं बढ़ाता है और उन्हें समानांतर में चलाता है, लेकिन इसके बजाय पुन: उपयोग करता है धागे और एक के बाद एक काम करता है)। जब मैं महंगे नेटवर्क कॉल कर रहा हूं तो यह बहुत धीमा है। तो मैंने सोचा कि मैं अपना स्वयं का एसिंक फ़ंक्शन लिखूंगा। मैं हालांकि अटक गया हूँ, std :: वादा कहाँ रहना चाहिए? 1) थ्रेड फ़ंक्शन, 2) async फ़ंक्शन, या 3) कॉलर फ़ंक्शन।std :: async को अपने संस्करण के साथ बदलना, लेकिन std :: वादा कहाँ रहना चाहिए?

कोड:

#include <future> 
#include <thread> 
#include <iostream> 
#include <string> 
#include <vector> 

std::string thFun() { 
    throw std::exception("bang!"); 
    return "val"; 
} 

std::future<std::string> myasync(std::promise<std::string>& prms) { 
//std::future<std::string> myasync() { 
    //std::promise<std::string> prms; //needs to outlive thread. How? 

    std::future<std::string> fut = prms.get_future(); 
    std::thread th([&](){ 
     //std::promise<std::string> prms; //need to return a future before... 
     try { 
      std::string val = thFun(); 

      prms.set_value(val); 

     } catch(...) { 
      prms.set_exception(std::current_exception()); 
     } 

    }); 

    th.detach(); 
    return fut; 
} 

int main() { 

    std::promise<std::string> prms; //I really want the promise hidden iway in the myasync func and not live here in caller code but the promise needs to outlive myasync and live as long as the thread. How do I do this? 
    auto fut = myasync(prms); 

    //auto fut = myasync(); //Exception: future already retrieved 

    try { 
     auto res = fut.get(); 
     std::cout << "Result: " << res << std::endl; 

    } catch(const std::exception& exc) { 
     std::cout << "Exception: " << exc.what() << std::endl; 
    } 

} 

मैं नहीं कर सकते तथ्य यह है कि std :: वादा async समारोह से अधिक जीवित करने की जरूरत है अतीत मिलता है (और धागे के रूप में के रूप में लंबे समय तक जीवित) प्रतीत होते हैं इसलिए वादा नहीं कर सकते एक के रूप में जीवित async func में स्थानीय चर। लेकिन std :: वादा कॉलर कोड में नहीं रहना चाहिए, क्योंकि कॉलर को केवल वायदा के बारे में जानना आवश्यक है। और मैं नहीं जानता कि वादा को थ्रेड फ़ंक्शन में कैसे बनाया जाए क्योंकि एसिंक को भविष्य को वापस करने की आवश्यकता है इससे पहले कि यह थ्रेड func भी कॉल करे। मैं इस पर अपने सिर खरोंच कर रहा हूँ।

किसी को भी कोई विचार है?

संपादित करें: मैं इसे यहां हाइलाइट कर रहा हूं क्योंकि शीर्ष टिप्पणी थोड़ा गलत है। जबकि std :: asycn के लिए डिफ़ॉल्ट को dererred मोड होने की अनुमति है, जब std :: launch :: async की लॉन्च नीति स्पष्ट रूप से सेट की जाती है, तो इसे "जैसे" थ्रेड उत्पन्न होते हैं और एक साथ चलते हैं (एन में शब्द देखें .cppreference.com/w/सीपीपी/धागा/async)। पेस्टबिन.com/5dWCjjNY में एक मामले के लिए उदाहरण देखें जहां यह बनाम 20011 में व्यवहार नहीं किया गया है। समाधान बहुत अच्छा काम करता है और 10.1

संपादित करें 2: एमएस ने बग को ठीक किया है। यहाँ और जानकारी:

future<string> myasync() 
{ 
    auto prms = make_shared<promise<string>>(); 

    future<string> fut = prms->get_future(); 

    thread th([=](){ 

     try { 
      string val = thFun(); 
      // ... 
      prms->set_value(val); 

     } catch(...) { 
      prms->set_exception(current_exception()); 
     } 

    }); 

    th.detach(); 

    return fut; 
} 

ढेर पर वादा आवंटित, और फिर लैम्ब्डा को पारित-दर-मूल्य [=] एक shared_ptr इसे करने के लिए के माध्यम से: https://connect.microsoft.com/VisualStudio/feedback/details/735731/std-async-std-launch-async-does-not-behave-as-std-thread

+9

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

+1

भविष्य में, कृपया बाहरी कोड से जोड़ने के बजाय अपने कोड को सीधे अपने प्रश्न में रखें। – ildjarn

+0

@ निकोल। क्या आपको यकीन है? जैसा कि मैं समझता हूं कि std :: launch :: async का उपयोग करते समय इसे कार्य करना चाहिए जैसे कि धागा उत्पन्न हुआ था। Http://en.cppreference.com/w/cpp/thread/async के अनुसार "यदि नीति और std :: launch :: async! = 0 (async बिट सेट है), निष्पादन के एक नए धागे को स्पॉन्स करता है जैसे कि std :: thread (f, args ...), सिवाय इसके कि यदि फ़ंक्शन एफ एक मान देता है या अपवाद फेंकता है, तो यह साझा स्थिति में संग्रहीत किया जाता है जो std :: भविष्य के माध्यम से सुलभ होता है कि async कॉलर पर वापस आती है। " – petke

उत्तर

21

यहाँ एक समाधान है।

+2

वाह ! यह काम करता है। अगर मैं कर सकता तो मैं आपको दस लाख अंक दूंगा। आपने मेरा सप्ताह बनाया – petke

5

आपको नए धागे में वादा को स्थानांतरित करने की आवश्यकता है। एंड्रयू टॉमज़ोस का जवाब साझा स्वामित्व के साथ std::promise बनाकर करता है, ताकि दोनों धागे वादे का मालिक हो सकें, और जब वर्तमान व्यक्ति वर्तमान दायरे से वापस आ जाए तो केवल नए धागे का वादा होता है, यानी स्वामित्व स्थानांतरित कर दिया गया है। लेकिन std::promise चल रहा है इसलिए इसे सीधे नए धागे में ले जाना संभव है, सिवाय इसके कि इसे कैप्चर करने का "स्पष्ट" समाधान काम नहीं करता है क्योंकि लैम्ब्डा केवल प्रतिलिपि द्वारा (या संदर्भ द्वारा, काम नहीं करेगा क्योंकि आपको एक खतरनाक संदर्भ मिलेगा।)

हालांकि, std::thread नए धागे के प्रारंभ समारोह में रैवल्यू ऑब्जेक्ट्स को पारित करने का समर्थन करता है। तो आप मान द्वारा एक std::promise तर्क लेने के लिए लैम्ब्डा घोषणा कर सकते हैं, यानी बल्कि यह कब्जा करने से लैम्ब्डा को promise गुजरती हैं, और उसके बाद std::thread जैसे के तर्कों

std::future<std::string> myasync() { 
    std::promise<std::string> prms; 

    std::future<std::string> fut = prms.get_future(); 
    std::thread th([&](std::promise<std::string> p){ 
     try { 
      std::string val = thFun(); 

      p.set_value(val); 

     } catch(...) { 
      p.set_exception(std::current_exception()); 
     } 

    }, std::move(prms)); 

    th.detach(); 
    return fut; 
} 

इस के लिए कदम से एक में वादा के लिए कदम std::thread ऑब्जेक्ट में वादा करें, जो उसके बाद लैंबडा के पैरामीटर p में इसे (नए धागे के संदर्भ में) ले जाता है।

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