2017-03-28 15 views
24
#include <cstdlib> 
#include <thread> 
#include <chrono> 
#include <iostream> 

using namespace std; 
using namespace std::literals; 

struct A 
{ 
    int n_ = 0; 
    A(int n) : n_(n) { cout << "A:" << n_ << endl; } 
    ~A() { cout << "~A:" << n_ << endl; } 
}; 

A a1(1); 

int main() 
{ 
    std::thread([]() 
    { 
     static A a2(2); 
     thread_local A a3(3); 
     std::this_thread::sleep_for(24h); 
    }).detach(); 

    static A a4(4); 
    thread_local A a5(5); 

    std::this_thread::sleep_for(1s); 
    std::exit(0); 
} 

मेरा कंपाइलर clang 5.0-std=c++1z के साथ है।`std :: exit` क्यों उम्मीदवारों को अपेक्षित रूप से ट्रिगर नहीं करता है?

उत्पादन इस प्रकार है: है

A:1 
A:2 
A:4 
A:5 
A:3 
~A:5 
~A:2 
~A:4 
~A:1 

ध्यान दें कि वहाँ कोई ~A:3 है, जो वस्तु A a3 विलुप्त नहीं किया गया है।

हालांकि, cppref के अनुसार:

std::exit सामान्य कार्यक्रम समाप्ति होने के लिए कारण बनता है। कई सफाई कदम प्रदर्शन किए गए:

थ्रेड स्थानीय भंडारण अवधि के साथ वस्तुओं के विनाशक ... कहने की गारंटी है।

+0

क्योंकि आप इसे अलग करते हैं, मुझे लगता है। – SingerOfTheFall

+1

क्या यह http://stackoverflow.com/questions/19744250/what-happens-to-a-detached-thread-when-main-exits का डुप्लिकेट है? –

+1

नहीं। यह वही है भले ही थ्रेड अलग नहीं हो। – xmllmx

उत्तर

37

थ्रेड स्टोरेज अवधि वाले ऑब्जेक्ट्स केवल exit पर कॉल किए गए थ्रेड के लिए नष्ट होने की गारंटी है। का हवाला देते हुए सी ++ 14 (N4140), [support.start.term] 18.5/8 (जोर मेरा):

[[noreturn]] void exit(int status) 

समारोह exit() इस अंतर्राष्ट्रीय मानक में अतिरिक्त व्यवहार है:

  • सबसे पहले, थ्रेड स्टोरेज अवधि के साथ ऑब्जेक्ट्स और वर्तमान थ्रेड से जुड़े हुए हैं। अगला, स्थैतिक संग्रहण अवधि वाले ऑब्जेक्ट नष्ट हो जाते हैं और atexit पर कॉल करके पंजीकृत फ़ंक्शन को कॉल किया जाता है। विनाश और कॉल के आदेश के लिए 3.6.3 देखें। (स्वचालित वस्तुओं exit() बुला की वजह से नष्ट नहीं कर रहे हैं।) नियंत्रण एक पंजीकृत समारोह exit द्वारा कहा जाता है क्योंकि समारोह एक फेंक दिया अपवाद के लिए एक हैंडलर प्रदान नहीं करता है छोड़ देता है, std::terminate() बुलाया जाएगा (15.5.1)।
  • इसके बाद, सभी खुले सी धाराओं अलिखित बफ़र डेटा के साथ (के रूप में समारोह हस्ताक्षर <cstdio> में घोषित द्वारा मध्यस्थता) प्लावित कर रहे हैं, सभी खुले सी धाराओं बंद हो जाती हैं, और सभी फ़ाइलों को बनाया बुला tmpfile() हट जाते हैं।
  • अंत में, होस्ट वातावरण में नियंत्रण वापस कर दिया जाता है। यदि स्थिति शून्य है या EXIT_SUCCESS है, तो स्थिति का कार्यान्वयन-परिभाषित रूप सफल समाप्ति वापस कर दिया गया है। यदि स्थिति EXIT_FAILURE है, तो असफल समाप्ति की स्थिति का कार्यान्वयन-परिभाषित रूप वापस कर दिया जाता है। अन्यथा वापस लौटाई गई स्थिति कार्यान्वयन-परिभाषित है।

मानक इसलिए धागा भंडारण एक exit बुला के अलावा अन्य धागे के साथ जुड़े अवधि के साथ वस्तुओं के विनाश की गारंटी नहीं है।

+10

यह इंगित करता है कि cppreference (प्रश्न में उद्धृत) सी ++ - विनिर्देश के अनुरूप नहीं है; और इसे उस वेब साइट पर एक बग के रूप में रिपोर्ट किया जाना चाहिए। –

+5

@ हंसऑल्सन: cppreference.com एक विकी है, इसलिए इसे एक बग के रूप में रिपोर्ट करने के बजाय, यदि आप चाहें तो इसे स्वयं ठीक कर सकते हैं। :-) – ruakh

14

समस्या यह है कि जब आप प्रक्रिया से बाहर निकलेंगे, तो धागा जबरन मार डाला जाएगा (सबसे आधुनिक बहु-कार्य संचालन प्रणालियों पर) जबरन मार डाला जाएगा। धागे की यह हत्या ओएस स्तर पर होती है, और ओएस वस्तुओं या विनाशकों के बारे में कुछ भी नहीं जानता है।

+2

मुझे खेद है, लेकिन मुझे नहीं लगता कि यह प्रश्न का उत्तर देता है। 'std :: exit 'प्रक्रिया से बाहर निकलने से पहले क्लीनअप का एक गुच्छा करता है, और यही वह सफाई है जिसे ओपी पूछ रहा है। प्रक्रिया समाप्त होने के बाद कोई भी विनाशकों को * कॉल करने की उम्मीद नहीं कर रहा था। – ruakh

+0

std :: निकास ओएस स्तर का फ़ंक्शन या सिस्टम कॉल नहीं है। यह एक सी ++ मानक पुस्तकालय समारोह है, क्योंकि यह सी ++ भाषा संरचनाओं के बारे में पता होगा। चाहे ओएस ऑब्जेक्ट्स के बारे में जानता हो या यदि कोई ओएस चल रहा है तो अप्रासंगिक है। – josefx

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