2017-03-28 7 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 a3가 파괴되지 않은 개체를 의미하며 ~A:3가없고

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

참고있다. cppref에 따른 그러나

:

std::exit 발생하는 통상 프로그램을 종료시킨다. 몇 가지 정리 단계는 입니다.

스레드 로컬 저장 기간을 가진 개체의 소멸자는 ... 이 호출되도록 보장됩니다.

+0

당신이 그것을 분리했기 때문에, 나는 생각한다. – SingerOfTheFall

+1

이것은 http://stackoverflow.com/questions/19744250/what-happens-to-a-detached-thread-when-main-exits의 복제본입니까? –

+1

아니요 스레드가 분리되지 않은 경우에도 마찬가지입니다. – xmllmx

답변

37

스레드 저장 기간이있는 객체는 exit을 호출하는 스레드에서만 삭제된다는 보장이 있습니다. 인용 C++ 14 (N4140), support.start.term] 18.5/8 (강조 광산)

[[noreturn]] void exit(int status) 

exit() 함수는이 표준에 추가적인 문제 가지고

  • 을 먼저 스레드 저장 기간이 이고 현재 스레드 인과 연결된 개체가 삭제됩니다. 다음으로 정적 저장 기간을 가진 객체가 파괴되고 atexit 을 호출하여 등록 된 함수가 호출됩니다. 폐기 및 호출 순서는 3.6.3을 참조하십시오. 예외가 throw 된 예외에 대해 처리기를 제공하지 않기 때문에 컨트롤이 exit에 의해 호출 된 등록 된 함수를 벗어나는 경우 (15.5.1) std::terminate()이 호출됩니다. tmpfile() 제거한 호출
  • 다음, 미기록 버퍼링 데이터 (<cstdio> 선언 함수 서명 매개로)중인 모든 C 스트림 열려 C 스트림이 닫혀 플러시되고, 모든 파일이 생성.
  • 마지막으로 제어가 호스트 환경으로 리턴됩니다. 상태가 0 또는 EXIT_SUCCESS 인 경우 구현이 정의한 상태 성공 종료 양식이 반환됩니다. 상태가 EXIT_FAILURE 인 경우 구현 실패로 인해 구현이 정의한 상태 실패 양식이 반환됩니다. 그렇지 않으면 반환 된 상태는 구현에 따라 정의됩니다.

표준 그러므로 exit를 호출하는 것보다 다른 스레드와 관련된 스레드 저장 기간이 객체의 파괴를 보장하지 않습니다.

+10

cppreference (질문에서 인용)가 C++ 사양과 일치하지 않음을 나타냅니다. 해당 웹 사이트의 버그로보고되어야합니다. –

+5

@HansOlsson : cppreference.com은 위키입니다. 버그로보고하기보다는 원할 경우 직접 수정할 수 있습니다. :-) – ruakh

14

여기서 문제는 프로세스를 종료 할 때 스레드가 (대부분의 최신 멀티 태스킹 운영 체제에서) 강제로 종료된다는 것입니다. OS 레벨에서이 쓰레드가 삭제되고 OS는 객체 나 소멸자에 대해 아무것도 모릅니다.

+2

죄송하지만이 질문에 전혀 대답하지 않는다고 생각합니다. 'std :: exit'는 프로세스를 종료하기 전에 정리 작업을 수행합니다. 이것은 OP가 요청하는 정리 작업입니다. 아무도 프로세스가 종료 된 후에 소멸자가 호출 될 것이라고 예상하지 않았습니다. – ruakh

+0

std :: exit는 OS 레벨 함수 또는 시스템 호출이 아닙니다. C++ 표준 라이브러리 함수이므로 C++ 언어 구조를 인식합니다. OS가 객체에 대해 알고 있는지 또는 전혀 실행중인 OS가 없는지는 관련이 없습니다. – josefx