2017-09-12 2 views
6

일부 코드를 비동기 적으로 실행할 수있는 클래스가 있고 비동기 코드가 해당 클래스 인스턴스를 사용하여 멤버 함수 호출, 데이터 멤버 읽기 등을 수행한다고 가정합니다. 분명히 클래스 인스턴스는 이러한 액세스를 위해 백그라운드 스레드보다 오래 있어야합니다. 안전하다. 그것은 소멸자의 배경 스레드에 합류하여 이것을 보장하는 것으로 충분합니까? 예를 들어 :소멸자에 가입하여 비동기 작업을 기다리는 것이 안전합니까?

#include <iostream> 
#include <thread> 

class foo final 
{ 
public: 
    foo() = default; 

    void bar() { 
     std::cout << "Hopefully there's nothing wrong with using " << this << "\n"; 
    } 

    void bar_async() { 
     if (!m_thread.joinable()) { 
      m_thread = std::thread{&foo::bar, this}; 
     } 
    } 

    ~foo() { 
     if (m_thread.joinable()) { 
      std::cout << "Waiting for " << m_thread.get_id() << "\n"; 
      m_thread.join(); 
     } 
    } 

private: 
    std::thread m_thread; 
}; 

int main() { 
    foo f; 
    f.bar_async(); 
} 

는 특히, 나는 object lifetime rules에 대해 걱정 : 소멸자의 실행이 시작되면

소멸자 사소한없는 클래스 유형의 객체에 대한

는 수명이 끝납니다.

... 물체의 수명이 끝난 후 점유하고 개체를 재사용하거나 해제 저장 전에 미정되는 객체를 식별 glvalue 표현의 다음 용도 ...

  • 비 정적 데이터 멤버에 대한 액세스 또는 비 정적 멤버 함수에 대한 호출.

는하지만 나에게 위의 엄격한 독서는 또한 ~foo() 내부에서 this->bar()를 호출하면 바로 "분명히"사실이 아니다, 이는 정의되지 않은 것을 의미한다.

+1

'최종'는 많은 문제를 해결합니다. 당신이 '최종'이 아니라면 극도로 조심하십시오. – Yakk

+0

실용적 또는 법률주의적인 질문입니까? – curiousguy

+0

@curiousguy Legalistic –

답변

3

cppreference가 맞지만 소멸자 내부가 아닌 객체에서 멤버에 액세스하는 것에 대해 이야기하고 있습니다. [class.cdtor]/1을 보면

으로 나타납니다. 생성자가 실행을 시작하기 전에 비 정적 인 생성자가있는 객체의 경우 비 정적 멤버 또는 객체의 기본 클래스를 참조하십시오. 정의되지 않은 동작. 중요하지 않은 소멸자가있는 객체의 경우 소멸자가 실행을 마친 후 객체의 비 정적 구성원 또는 기본 클래스를 참조하는 은 정의되지 않은 동작 인이됩니다.

그래서, 같은 우리가 소멸자에 우리가 여전히 소멸자 끝의 범위까지 파괴되지 않는 것과 구성원 개체로 작업 할 수 있습니다 강조 광산.

그럼 스레드에서 join을 호출하는 것이 좋습니다. 만약 그렇지 않다면 당신이 그것에 대해 생각한다면 락 가드와 같은 것들은 그들이 참조하는 뮤텍스에 접근하는 것이 정의되지 않은 행동이라면 쓸모 없게 될 것입니다.

+0

그래, 나는 소멸자의 코드에 대해 특별히 걱정하지 않는다. 정말로 바둑 (소멸자와 동시에 실행할 수있는 다른 스레드의 bar() 호출이다. –

+0

@ TavianBarnes 다른 스레드는 무엇입니까? 멤버 스레드를 시작하려면'bar_async()'를 호출해야합니다. 자신의 예제에서 객체가 파괴되는 것과 동시에이 함수를 호출 할 수 없습니다. – NathanOliver

+0

member thread가'bar()'를 호출 중임 –

0

내 직감은 아니오. thread :: join은 예외를 throw 할 수 있기 때문에 소멸자를 이스케이프하는 예외는 원하지 않기 때문입니다. try catch에 랩핑하고 예외를 제대로 처리하더라도 괜찮을 수 있습니다.

+3

이러한 예외의 원인은 기본적으로 프로그래밍 오류입니다. 직접 참여하려고 시도하거나 조인 할 수없는 스레드에 참가하려고합니다. – MSalters

+0

예외가 catch되지 않고 throw 된 스레드에서 처리되는 경우 스레드 내의 예외가 즉시 프로그램을 종료합니다. - 스레드에 합류하는 소멸자는 전혀 영향을받지 않습니다. – CAF

관련 문제