2013-02-07 7 views
5

MSVC2012 का उपयोग करना,std :: packaged_task <void()> मान्य क्यों है?

निम्नलिखित कोड संकलन और अपेक्षा के अनुरूप

std::packaged_task< int() > task([]()->int{ std::cout << "hello world" << std::endl; return 0; }); 
std::thread t(std::move(task)); 
t.join(); 

चलेंगे, जबकि निम्न कोड संकलन और चलाने

std::packaged_task< void() > task([](){ std::cout << "hello world" << std::endl; }); 
std::thread t(std::move(task)); 
t.join(); 

क्यों है ऐसा करने के लिए असफल हो जायेगी?

संपादित करें: समाधान के लिए, यह एक समारोह है कि रिटर्न शून्य

std::promise<void> promise; 
auto future = promise.get_future(); 
std::thread thread([](std::promise<void> &p){ std::cout << "hello world" << std::endl; p.set_value(); }, std::move(promise)); 
future.wait(); 

नोट वहाँ vs2012 पुस्तकालय में एक बग है कि पर std :: एक एसटीडी पाने के लिए वादा :: भविष्य उपयोग करना संभव है std :: थ्रेड के साथ जो आपको एल-वैल्यू संदर्भ के रूप में वादा करने के लिए मजबूर करता है और वादा को स्थानांतरित करता है, यदि आप मान द्वारा या आर-वैल्यू संदर्भ द्वारा वादा पास करते हैं तो यह संकलित नहीं होगा। ऐसा माना जाता है क्योंकि कार्यान्वयन std :: bind() का उपयोग करता है जो अपेक्षित व्यवहार नहीं करता है।

+6

दिलचस्प ... संकलन करते समय दूसरा क्या त्रुटि देता है? – Yuushi

+0

यह शायद एमएसवीसी ++ में एक बग है। –

+4

जो मैंने के कार्यान्वयन में पाया है, वह अंततः फ़ंक्शन ऑब्जेक्ट निष्पादन स्थिति के अपने संग्रहण पर आता है, विशेष रूप से '_State_manager' नामक टेम्पलेट वर्ग में। 'शून्य' राज्य के लिए '_State_manager' का कोई विशेषज्ञता नहीं है, जो कि एक बग पसंद है। मैं भी लंच के लिए पूरी तरह से बाहर हो सकता है, लेकिन जहां यह प्रतीत होता है कि सबकुछ अलग हो जाता है। – WhozCraig

उत्तर

5

यह MSVC2012 में एक बग है। थ्रेड लाइब्रेरी कार्यान्वयन में कुछ बग हैं जो MSVC2012 के साथ जहाजों हैं। मैंने अपने ब्लॉग पोस्ट में इसकी आंशिक सूची पोस्ट की है जो इसे मेरे वाणिज्यिक जस्ट :: थ्रेड लाइब्रेरी: http://www.justsoftwaresolutions.co.uk/news/just-thread-v1.8.0-released.html

+0

"वीएस2012 लाइब्रेरी के साथ, जब std :: async std :: launch :: async की लॉन्च नीति के साथ प्रयोग किया जाता है, तो लौटा हुआ std :: भविष्य के उदाहरण का विनाशक धागे को पूरा करने की प्रतीक्षा नहीं करता है।" - मैं इसे एक विकल्प बनाउंगा। तर्क यह है कि मानकों के पाठ में एक बग है जो आकर्षक है। – Yakk

+1

'std :: async' के लिए मानक शब्दकोष सावधानी से चुना गया था, और माइक्रोसॉफ्ट जानबूझकर मानक के खिलाफ जाने का फैसला किया। यह मानक में एक बग नहीं है, हालांकि कुछ मानते हैं कि यह एक खराब विकल्प था। –

+0

यह निराशाजनक है, इनमें से कुछ बग परीक्षण मामलों के सबसे सरल द्वारा पकड़े गए होंगे। मुझे माइक्रोसॉफ्ट से ज्यादा उम्मीद थी। – aCuria

3

यह जीसीसी 4.7.2 में काम करता है:

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

int main() { 
    std::packaged_task< void() > task([](){ std::cout << "hello world" << std::endl; }); 
    std::thread t(std::move(task)); 
    t.join(); 
    std::packaged_task< int() > task2([]()->int{ std::cout << "hello world" << std::endl; return 0; }); 
    std::thread t2(std::move(task2)); 
    t2.join(); 
} 

@WhozCraig के पुरातत्व के साथ मिलकर संकेत मिलता है कि यह शायद MSVC2012 में एक बग है।

एक कामकाज के लिए, struct Nothing {}; या nullptr_t का उपयोग अपने वापसी मूल्य के रूप में करने का प्रयास करें?

2

समस्या अभी भी एमएसवीएस 2013 आरसी में है, लेकिन मैंने यह अस्थायी पैच बनाया है जबकि एमएस इसे सुधारता है। यह शून्य (...) के लिए packaged_task का एक विशेषज्ञता है, इसलिए मैं इसे हेडर फ़ाइल में डालने का सुझाव देता हूं और इसे मानक शीर्षलेख के बाद भी शामिल करता हूं। नोट करें कि make_ready_at_thread_exit() लागू नहीं किया गया है और कुछ फ़ंक्शंस का पूरी तरह से परीक्षण नहीं किया गया है, पर उपयोग करें आपका जोखिम

namespace std { 

template<class... _ArgTypes> 
class packaged_task<void(_ArgTypes...)> 
{ 
    promise<void> _my_promise; 
    function<void(_ArgTypes...)> _my_func; 

public: 
    packaged_task() { 
    } 

    template<class _Fty2> 
    explicit packaged_task(_Fty2&& _Fnarg) 
     : _my_func(_Fnarg) { 
    } 

    packaged_task(packaged_task&& _Other) 
     : _my_promise(move(_Other._my_promise)), 
     _my_func(move(_Other._my_func)) { 
    } 

    packaged_task& operator=(packaged_task&& _Other) { 
     _my_promise = move(_Other._my_promise); 
     _my_func = move(_Other._my_func); 
     return (*this); 
    } 

    packaged_task(const packaged_task&) = delete; 
    packaged_task& operator=(const packaged_task&) = delete; 

    ~packaged_task() { 
    } 

    void swap(packaged_task& _Other) { 
     _my_promise.swap(_Other._my_promise); 
     _my_func.swap(_Other._my_func); 
    } 

    explicit operator bool() const { 
     return _my_func != false; 
    } 

    bool valid() const { 
     return _my_func != false; 
    } 

    future<void> get_future() { 
     return _my_promise.get_future(); 
    } 

    void operator()(_ArgTypes... _Args) { 
     _my_func(forward<_ArgTypes>(_Args)...); 
     _my_promise.set_value(); 
    } 

    void reset() { 
     swap(packaged_task()); 
    } 
}; 

}; // namespace std 
संबंधित मुद्दे