मुझे std :: thread :: detach का उपयोग कब करना चाहिए?


140

कभी-कभी मुझे std::threadअपने एप्लिकेशन को गति देने के लिए उपयोग करना पड़ता है । मुझे यह भी पता है join()कि एक धागा पूरा होने तक इंतजार किया जाता है। यह समझना आसान है, लेकिन कॉल करने detach()और इसे न करने के बीच क्या अंतर है?

मुझे लगा कि इसके बिना detach(), थ्रेड का तरीका स्वतंत्र रूप से एक थ्रेड का उपयोग करके काम करेगा।

कोचिंग नहीं:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called without detach");
    });

    //some code here
}

कोचिंग के साथ कॉलिंग:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called with detach");
    });

    t.detach();

    //some code here
}


दोनों stdऔर boostधागे की है detachऔर joinPOSIX धागे के बाद बारीकी से मॉडलिंग की।
एन। 'सर्वनाम' मी।

जवाबों:


149

के विध्वंसक में std::thread, std::terminateकहा जाता है:

  • धागा शामिल नहीं था (के साथ t.join())
  • और (साथ t.detach()) अलग नहीं किया गया था

इस प्रकार, आप हमेशा या तो चाहिए joinया detachएक धागा से पहले निष्पादन की बहती नाशक तक पहुँचता है।


जब कोई कार्यक्रम समाप्त होता है (यानी, mainरिटर्न) तो पृष्ठभूमि में निष्पादित शेष अलग किए गए थ्रेड्स का इंतजार नहीं किया जाता है; इसके बजाय उनके निष्पादन को निलंबित कर दिया गया है और उनके धागे-स्थानीय वस्तुओं को नष्ट कर दिया गया है।

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


तो, आप का उपयोग करना चाहिए joinया detach?

  • उपयोग join
  • जब तक आपको अधिक लचीलेपन की आवश्यकता नहीं होती है और आप अपने आप ही थ्रेड के पूरा होने तक प्रतीक्षा करने के लिए एक सिंक्रनाइज़ेशन तंत्र प्रदान करने के लिए तैयार रहते हैं , जिसमें आप उपयोग कर सकते हैंdetach

अगर मैं pthread_exit (NULL) को कॉल करूंगा; मुख्य में () तब निकास () को मुख्य () से नहीं बुलाया जाएगा और इसलिए कार्यक्रम निष्पादन को जारी रखेगा जब तक कि सभी अलग किए गए धागे पूरे नहीं होंगे। फिर बाहर निकलें () कहा जाएगा।
सूयर्टन

1
@ मैथ्यू, हम std के विध्वंसक में क्यों शामिल नहीं हो सकते हैं :: धागा?
जॉन स्मिथ

2
@ जॉनसन: एक उत्कृष्ट प्रश्न! जब आप शामिल होते हैं तो क्या होता है? आप इंतजार करें जब तक धागा पूरा न हो जाए। यदि एक अपवाद को फेंक दिया जाता है, तो विनाशकों को निष्पादित किया जाता है ... और अचानक थ्रेड समाप्त होने तक आपके अपवाद का प्रसार निलंबित हो जाता है। इसके नहीं होने के कई कारण हैं, विशेष रूप से अगर यह वर्तमान में निलंबित धागे से इनपुट पर प्रतीक्षा कर रहा है! इसलिए डिजाइनरों ने एक विवादास्पद डिफ़ॉल्ट चुनने के बजाय इसे एक स्पष्ट विकल्प बनाने के लिए चुना।
मैथ्यू एम।

@ मैथ्यू मुझे लगता है कि आपका मतलब है ज्वाइन कॉल () एसटीडी से पहले :: थ्रेड का डिस्ट्रक्टर पहुंच जाता है। आप (और?) में शामिल हो सकते हैं () एक संलग्न वर्ग के विध्वंसक?
जोस क्विनेत्रो

4
@ जोसेक्इन्टेइरो: वास्तव में, अन्य संसाधनों के विपरीत, यह एक विध्वंसक से शामिल नहीं होने की सलाह दी जाती है । समस्या यह है कि जुड़ने से एक धागा समाप्त नहीं होता है , यह केवल इसके समाप्त होने की प्रतीक्षा करता है , और इसके विपरीत आपके पास एक संकेत है जिसके कारण धागा समाप्त होने का कारण आपको लंबे समय तक इंतजार करना पड़ सकता है ... वर्तमान धागे को अवरुद्ध करना जिसका स्टैक अनचाही हो रही है और इस मौजूदा धागे को कभी समाप्त होने से रोक रही है, इस प्रकार इसके लिए प्रतीक्षा करने वाले धागे को अवरुद्ध कर रही है, आदि ... इसलिए, जब तक कि आप निश्चित नहीं हैं कि आप किसी दिए गए धागे को उचित समय में रोक सकते हैं, तब तक इंतजार करना सबसे अच्छा है एक विध्वंसक में।
मैथ्यू एम।

25

आपको कॉल करना चाहिए detachकि आप थ्रेड के पूरा होने का इंतजार नहीं कर रहे हैं, joinलेकिन इसके बजाय थ्रेड बस तब तक चलता रहेगा जब तक कि यह पूरा नहीं हो जाता है और फिर मुख्य थ्रेड के बिना विशेष रूप से इंतजार किए बिना समाप्त हो जाता है।

detachमूल रूप से लागू करने में सक्षम होने के लिए आवश्यक संसाधनों को जारी करेगा join

यदि एक धागा ऑब्जेक्ट को उसके जीवन समाप्त होता है और न यह एक गंभीर त्रुटि है joinऔर न ही detachबुलाया गया है; इस मामले terminateमें चालान किया गया है।


12
आपको उल्लेख करना चाहिए, उस समाप्ति को विध्वंसक में कहा जाता है, अगर धागा न तो शामिल हुआ है और न ही अलग किया गया है
nosid

11

जब आप थ्रेड को अलग करते हैं तो इसका मतलब है कि join()बाहर निकलने से पहले आपको इसे करने की आवश्यकता नहीं है main()

थ्रेड लाइब्रेरी वास्तव में नीचे दिए गए प्रत्येक ऐसे थ्रेड का इंतजार करेगी , लेकिन आपको इसकी परवाह नहीं करनी चाहिए।

detach()मुख्य रूप से उपयोगी होता है जब आपके पास एक कार्य होता है जिसे पृष्ठभूमि में किया जाना होता है, लेकिन आप इसके निष्पादन की परवाह नहीं करते हैं। यह आमतौर पर कुछ पुस्तकालयों के लिए एक मामला है। वे चुपचाप एक पृष्ठभूमि कार्यकर्ता धागा बना सकते हैं और इसे अलग कर सकते हैं ताकि आप इसे नोटिस भी न करें।


इस सवाल का जवाब नहीं है। उत्तर में मूल रूप से कहा गया है "जब आप अलग हो जाते हैं"।
रुबेंव

7

इस उत्तर शीर्षक में सवाल का जवाब देने के बजाय बीच का अंतर समझा के उद्देश्य से है joinऔर detach। तो कब std::thread::detachइस्तेमाल किया जाना चाहिए?

ठीक से बनाए रखा में सी ++ कोड का std::thread::detachउपयोग नहीं किया जाना चाहिए। प्रोग्रामर को यह सुनिश्चित करना चाहिए कि सभी निर्मित थ्रेड्स सभी अधिग्रहित संसाधनों को जारी करने और अन्य आवश्यक सफाई कार्यों को करने के लिए इनायत करते हैं। तात्पर्य यह है कि आह्वान करके धागों का स्वामित्व छोड़ देना detachकोई विकल्प नहीं है और इसलिए joinसभी परिदृश्यों में इसका उपयोग किया जाना चाहिए।

हालाँकि कुछ एप्लिकेशन पुराने पर निर्भर होते हैं और अक्सर अच्छी तरह से डिज़ाइन किए गए और समर्थित API नहीं होते हैं जो अनिश्चित काल के कार्यों को रोक सकते हैं। अन्य सामानों को अवरुद्ध करने से बचने के लिए एक समर्पित धागे में इन कार्यों के बढ़ते हुए आक्रमण एक आम बात है। इनायत से बाहर निकलने के लिए इस तरह के धागे को बनाने का कोई तरीका नहीं है इसलिए joinइच्छाशक्ति के उपयोग से प्राथमिक धागा अवरुद्ध हो जाएगा। यह एक ऐसी स्थिति है जब उपयोग detachकरने threadसे डायनामिक स्टोरेज अवधि के साथ ऑब्जेक्ट आवंटित करना और फिर जानबूझकर इसे लीक करना एक कम बुराई विकल्प होगा।

#include <LegacyApi.hpp>
#include <thread>

auto LegacyApiThreadEntry(void)
{
    auto result{NastyBlockingFunction()};
    // do something...
}

int main()
{
    ::std::thread legacy_api_thread{&LegacyApiThreadEntry};
    // do something...
    legacy_api_thread.detach();
    return 0;
}

1

Cppreference.com के अनुसार :

थ्रेड ऑब्जेक्ट से निष्पादन के थ्रेड को अलग करता है, जिससे निष्पादन को स्वतंत्र रूप से जारी रखने की अनुमति मिलती है। धागा बाहर निकलते ही किसी भी आवंटित संसाधनों को मुक्त कर दिया जाएगा।

अलग होने के बाद *thisअब किसी भी धागे का मालिक नहीं है।

उदाहरण के लिए:

  std::thread my_thread([&](){XXXX});
  my_thread.detach();

स्थानीय चर को नोटिस करें: my_threadजबकि जीवनकाल my_threadखत्म हो गया है, को नष्ट करने वाले std::threadको बुलाया std::terminate()जाएगा , और विध्वंसक के भीतर बुलाया जाएगा।

लेकिन अगर आप उपयोग करते हैं detach(), तो आपको my_threadअब और उपयोग नहीं करना चाहिए , भले ही जीवनकाल my_threadखत्म हो जाए, नए धागे से कुछ नहीं होगा।


ठीक है, मैंने जो अभी कहा था उसे वापस लेता हूं। @ TobySpeight
DinoStray

1
ध्यान दें कि यदि आप &लैम्ब्डा कैप्चर में उपयोग करते हैं, तो आप संदर्भ द्वारा एन्कोडिंग स्कोप के चर का उपयोग कर रहे हैं - ताकि आप सुनिश्चित करें कि किसी भी संदर्भ का जीवनकाल आपके थ्रेड जीवनकाल से अधिक लंबा हो।
डेविडजे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.