2014-05-11 23 views
8

मैं एक वर्ग का उपयोग करना चाहता हूं जो थ्रेड (या कई धागे) का प्रबंधन करता है।क्या कक्षा के सदस्य के रूप में std :: thread होने का कोई सुरक्षित तरीका है?

class MyClass{ 
private: 
    std::thread mythread; 
    void _ThreadMain(); 
public: 
    MyClass(); 
    // other fields 
} 

क्योंकि एक std::thread के लिए डिफ़ॉल्ट निर्माता व्यर्थ है, मैं MyClass निर्माता में स्पष्ट रूप से यह कॉल करने के लिए की आवश्यकता होगी: रचना का उपयोग करना, इस प्रकार दिखाई देगा

MyClass::MyClass() : mythread(&MyClass::_ThreadMain,this) {} 

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

void MyClass::Start(){ 
    // This time mythread is of type std::thread* 
    mythread = new std::thread(&MyClass::_ThreadMain,this); // One could use std::unique_pointer instead. 
} 

जो कि धागा ऊपर से निकाल देते थे:

एक स्पष्ट समाधान के बजाय std::thread के सूचक के उपयोग करने के लिए है, और किसी अन्य सदस्य समारोह जोड़ने होगा। इस मामले में कक्षा के निर्माण के बाद इसे बुलाया जाएगा, जो वास्तव में सुरक्षित होगा।

हालांकि, मुझे आश्चर्य है कि कोई उचित समाधान है जो मुझे इसके लिए पॉइंटर्स का उपयोग न करने की अनुमति देगा। ऐसा लगता है कि यह किसी भी तरह से संभव होना चाहिए (हे, कक्षा का निर्माण होने पर धागा लॉन्च करने का एक तरीका होना चाहिए!), लेकिन मैं ऐसी किसी भी चीज के साथ नहीं आ सकता जो परेशानियों का कारण नहीं बनता।

मैंने एक सशर्त चर का उपयोग करने पर विचार किया है ताकि _ThreadMain कन्स्ट्रक्टर ने अपना काम पूरा कर दिया हो, लेकिन कक्षा का निर्माण करने से पहले मैं इसका उपयोग नहीं कर सकता, है ना? (यह भी बेकार है, तो MyClass एक व्युत्पन्न वर्ग था होगा)

+7

'mythread = new std :: thread ('MyClass :: _ ThreadMain, this) पर' new' को छोड़ दें; ',' std :: thread' movable है! अपने वर्ग सदस्य समारोह को बांधने के लिए 'std :: bind' पर विचार करें। –

+1

जब तक आप आगे बढ़ने के लिए कहा जाता है तब तक आप धागे को प्रतीक्षा कर सकते हैं (बहुत शुरुआत में)। –

+1

यहां समस्या यह है कि यदि '_ThreadMain' विधि वर्चुअल है, तो थ्रेड गलत फ़ंक्शन को कॉल करेगा। मुझे इस पर समाधान देखने में बहुत दिलचस्पी होगी जहां कन्स्ट्रक्टर सही काम करता है। –

उत्तर

6

कोई बेहतर तरीका है, सामान्य रूप में, एक अलग Start समारोह की तुलना में है।

मान लीजिए MyClass कुछ भविष्य (अज्ञात) वर्ग Derived के लिए आधार वर्ग है। यदि धागा MyClass कन्स्ट्रक्टर रन (या इससे पहले) शुरू होता है, तो यह हमेशा Derived द्वारा ओवरराइड किए गए कुछ वर्चुअल फ़ंक्शन के "गलत" कार्यान्वयन को कॉल करने का जोखिम रखता है।

इससे बचने के लिए एक ही रास्ता धागा इंतजार जब तक के बाद Derived पूरी तरह से निर्माण किया है, और ऐसा करने के लिए एक ही रास्ता है के बाद Derived निर्माता धागा "जाना" बताने के लिए पूरा करता है कुछ अन्य समारोह कॉल करने के लिए है। .. जिसका मतलब है कि आपके पास Go फ़ंक्शन का अलग-अलग प्रकार का आह्वान होना चाहिए।

आप इसके बजाय अलग-अलग Start फ़ंक्शन के बजाय भी प्रतीक्षा कर सकते हैं और प्रतीक्षा की जटिलता को रोक सकते हैं।

[अपडेट]

ध्यान दें कि, जटिल कक्षाओं के लिए, "दो चरण निर्माण" एक मुहावरा कुछ लोगों द्वारा की सिफारिश की है। धागा शुरू करना "प्रारंभिक" चरण में निर्बाध रूप से फिट होगा।

4

आप चाल अर्थ विज्ञान के साथ संयोजन में एक धागा उपयोग कर सकते हैं:

class MyClass final 
{ 
private: 
    std::thread mythread; 
    void _ThreadMain(); 
public: 
    MyClass() 
     : mythread{} // default constructor 
    { 
     // move assignment 
     mythread = std::thread{&MyClass::_ThreadMain, this}; 
    } 
}; 

कदम असाइनमेंट ऑपरेटर निम्न पृष्ठ पर दर्ज है। विशेष रूप से, यह noexcept है और कोई नया धागा नहीं बनाया गया है।

+0

जब आप कोई थ्रेड ऑब्जेक्ट ले जाते हैं तो यह निष्पादन का एक नया धागा शुरू करता है, या क्या यह वास्तव में इसे स्थानांतरित करता है? – Ben

+3

यदि कोई vtable सूचक है तो यह समाधान परेशानी में भाग सकता है! Vtable सूचक को * कन्स्ट्रक्टर के ब्लॉक के बाद * प्रारंभ किया जाएगा! – Klaus

+2

आपके पास उन सभी चीजों के लिए टेम्पलेट्स हैं, है ना? मैं आपकी टिप्पणी को देखने से पहले एक टिप्पणी के रूप में अपनी टिप्पणी पोस्ट करने पर विचार कर रहा हूं, लेकिन वापस ले लिया गया ... –

1

कार्य को थ्रेड प्रबंधन और लॉन्चिंग से अलग करने पर विचार करें।

एक वर्ग एक धावक बनाता है और किसी भी सिंक्रनाइज़ेशन प्राइमेटिव्स की तरह snd, दूसरे इसे लॉन्च करने में हैंडल करता है। यह थ्रेडिंग शुरू होने से पहले विफल होने के लिए रननेबल के निर्माण की अनुमति देता है।

इसका मतलब यह भी है कि रननेबल इसे चलाने से पहले पूरी तरह से बनाया गया है।

अब पहले पास में धावक std::thread होगा, लेकिन कुछ सामान निरस्त करने और सफाई और निरंतरता के साथ मददगार हो सकता है।

रन ऑब्जेक्ट एक साधारण कॉल करने योग्य हो सकता है, या इसके साथ बातचीत करने के लिए रननेबल के लिए अतिरिक्त समर्थन जोड़ सकता है।

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