언제 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
}


모두 stdboost스레드 한 detachjoinPOSIX 스레드 후 밀접하게 모델링.
n. '대명사'm.

답변:


149

의 소멸자에서 다음과 같은 std::thread경우 std::terminate에 호출됩니다.

  • 스레드가 (와 t.join()) 결합되지 않았습니다
  • 하나와 (과 분리되지 않은 t.detach())

따라서 실행 흐름이 소멸자에 도달하기 전에 항상 하나 join또는 detach스레드 여야합니다 .


프로그램이 종료되면 (즉, main리턴) 백그라운드에서 실행중인 나머지 분리 된 스레드는 대기하지 않습니다. 대신 실행이 일시 중단되고 스레드 로컬 객체가 파괴됩니다.

결정적으로, 이것은 해당 스레드의 스택이 풀리지 않아 일부 소멸자가 실행되지 않음을 의미합니다. 이러한 소멸자가 수행해야 할 행동에 따라 프로그램이 충돌하거나 사망 한 것처럼 상황이 좋지 않을 수 있습니다. OS가 파일 등의 잠금을 해제하기를 원하지만 공유 메모리, 반으로 쓴 파일 등이 손상되었을 수 있습니다.


그래서 join또는 사용해야 detach합니까?

  • 사용하다 join
  • 더 많은 유연성이 필요하지 않고 독자적으로 스레드 완료를 기다릴 수있는 동기화 메커니즘을 제공하려는 경우를 제외하고는detach

pthread_exit (NULL)를 호출하면; main ()에서 exit ()는 main ()에서 호출되지 않으므로 분리 된 모든 스레드가 완료 될 때까지 프로그램이 계속 실행됩니다. 그런 다음 exit ()가 호출됩니다.
southerton

1
@Matthieu, 왜 std :: thread의 소멸자에 참여할 수 없습니까?
john smith

2
@ johnsmith : 훌륭한 질문입니다! 가입하면 어떻게 되나요? 스레드가 완료 될 때까지 기다립니다. 예외가 발생하면 소멸자가 실행되고 갑자기 스레드가 종료 될 때까지 예외 전파가 일시 중단됩니다. 현재 일시 중단 된 스레드에서 입력을 기다리는 경우에는 그렇지 않은 이유가 많이 있습니다! 따라서 설계자들은 논란의 여지가없는 기본값을 선택하는 대신 명시적인 선택을하기로했습니다.
Matthieu M.

@ Matthieu std :: thread의 소멸자에 도달하기 전에 join ()을 호출하는 것을 의미한다고 생각합니다. 둘러싼 클래스의 소멸자를 join () 할 수 있습니까?
Jose Quinteiro

4
@JoseQuinteiro : 실제로 다른 리소스와 달리 소멸자로부터 참여 하지 않는 것이 좋습니다 . 문제는 않습니다에 합류한다는 것이다 끝나지 스레드 것은, 그것은 단지 대기 가 끝날 때까지, 당신은 장소에 신호를 달리 당신은 ... 오랜 시간을 기다리고있을 수도 종료 스레드의 원인을 차단 누구의 스택 현재 스레드를 이 스레드 가 풀리고 현재 스레드 가 종료되는 것을 방지하여 스레드를 기다리는 스레드 등을 차단합니다. 따라서 주어진 스레드를 적절한 시간 내에 중지시킬 수 있다고 확신 하지 않는 한 기다리지 않는 것이 가장 좋습니다 소멸자에서.
Matthieu M.

25

detach스레드가 완료 될 때까지 기다리지 않으면 호출해야 join하지만 스레드는 완료 될 때까지 계속 실행 한 다음 주 스레드가 구체적으로 기다리지 않고 종료됩니다.

detach기본적으로 구현하는 데 필요한 리소스를 공개합니다 join.

스레드 객체의 수명을 종료하지 않고 둘 경우 치명적인 오류가 발생 join하거나 detach호출 된; 이 경우 terminate에 호출됩니다.


12
당신은 것을 언급해야 종료 스레드가 둘 다 한 경우, 소멸자 호출 에 가입하지 않고 분리 .
nosid

11

스레드를 분리하면 join()종료하기 전에 스레드가 필요하지 않습니다 main().

스레드 라이브러리는 실제로 이러한 각 스레드 가 main 아래를 기다릴 것이지만 신경 쓰지 않아야합니다.

detach()백그라운드에서 수행해야 할 작업이 있지만 실행에 신경 쓰지 않을 때 주로 유용합니다. 이것은 일반적으로 일부 라이브러리의 경우입니다. 백그라운드 작업자 스레드를 자동으로 작성하고 분리하여 눈치 채지 못할 수도 있습니다.


이것은 질문에 대답하지 않습니다. 대답은 기본적으로 "분리 할 때 분리합니다"입니다.
rubenvb

7

이 답변은 제목에 질문에 대답보다는 사이의 차이를 설명 목표로 join하고 detach. 언제 사용해야 std::thread::detach합니까?

올바르게 유지 관리되는 C ++ 코드 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 에 따르면 :

실행 스레드를 스레드 개체와 분리하여 실행을 독립적으로 계속할 수 있습니다. 스레드가 종료되면 할당 된 모든 자원이 해제됩니다.

detach를 호출하면 *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
&람다 캡처에서 사용하는 경우 엔 클로징 범위의 변수를 참조로 사용 하므로 참조 하는 수명이 스레드 수명보다 길어야합니다.
DavidJ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.