std :: thread가 여전히 실행 중인지 확인하는 방법은 무엇입니까?


84

a std::thread가 아직 실행 중인지 (플랫폼 독립적 인 방식으로) 어떻게 확인할 수 있습니까? 그것은 timed_join()방법 이 부족하고 joinable()그것을 의미하지 않습니다.

std::lock_guard스레드에 있는 뮤텍스를 잠그고 뮤텍스 의 try_lock()방법을 사용하여 여전히 잠겨 있는지 (스레드가 실행 중인지) 확인하려고 생각했지만 불필요하게 복잡해 보입니다.

더 우아한 방법을 알고 있습니까?

업데이트 : 명확하게 : 스레드가 깨끗하게 종료되었는지 확인하고 싶습니다. 이 목적을 위해 '매달려있는'스레드가 실행중인 것으로 간주됩니다.


스레드가 여전히 실행 중인지 확인하는 것은 예상 할 때만 중요 wait()하며 만약 그렇다면 wait()아직 실행 하지 않았다면 정의에 따라 실행 중이어야합니다. 그러나이 추론은 정확하지 않을 수 있습니다.
ereOn

사실 예외적 인 조건에서 종료되는 스레드가 있으며, 여전히 실행 중인지 메인 스레드에서 확인하고 싶지만 기다리지 않으려 고합니다.
kispaljr

1
달리기 란 정확히 무엇을 의미합니까? 대기 상태가 아니라 적극적으로 처리 중임을 의미합니까, 아니면 스레드가 여전히 존재하고 종료되지 않았 음을 의미합니까?
CashCow

항상 boost를 사용할 수 있습니다. :)
CashCow

4
만족스럽지 않다면 대답을 수락하지 않았어야합니다.
Nicol Bolas 2012

답변:


117

C ++ 11을 사용 std::async하고 std::future작업을 실행 하려는 경우의 wait_for기능을 사용 std::future하여 스레드가 다음과 같은 깔끔한 방식으로 여전히 실행 중인지 확인할 수 있습니다 .

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    /* Run some task on new thread. The launch policy std::launch::async
       makes sure that the task is run asynchronously on a new thread. */
    auto future = std::async(std::launch::async, [] {
        std::this_thread::sleep_for(3s);
        return 8;
    });

    // Use wait_for() with zero milliseconds to check thread status.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    auto result = future.get(); // Get result.
}

사용해야하는 경우 std::thread다음 std::promise개체를 가져 오는 데 사용할 수 있습니다 .

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a promise and get its future.
    std::promise<bool> p;
    auto future = p.get_future();

    // Run some task on a new thread.
    std::thread t([&p] {
        std::this_thread::sleep_for(3s);
        p.set_value(true); // Is done atomically.
    });

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

이 두 예제는 모두 다음을 출력합니다.

Thread still running

물론 작업이 완료되기 전에 스레드 상태가 확인되기 때문입니다.

그러나 다른 사람들이 이미 언급 한 것처럼하는 것이 더 간단 할 수 있습니다.

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::atomic<bool> done(false); // Use an atomic flag.

    /* Run some task on a new thread.
       Make sure to set the done flag to true when finished. */
    std::thread t([&done] {
        std::this_thread::sleep_for(3s);
        done = true;
    });

    // Print status.
    if (done) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

편집하다:

다음 std::packaged_task을 사용하는 std::thread것보다 더 깨끗한 솔루션 을 위해 함께 사용할 수도 있습니다 std::promise.

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a packaged_task using some task and get its future.
    std::packaged_task<void()> task([] {
        std::this_thread::sleep_for(3s);
    });
    auto future = task.get_future();

    // Run task on new thread.
    std::thread t(std::move(task));

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        // ...
    }

    t.join(); // Join thread.
}

2
좋은 대답입니다. 나는 어떤 리턴 값와 미래 <무효>하지 않고는 스레드를 작동 추가 할
kispaljr

이 코드의 이유는 무엇입니까 std::atomic<bool> done(false);? bool기본적으로 원자가 아닌가 ?
Hi-Angel

6
@YagamyLight C ++에서는 기본적으로 std::atomic. sizeof(bool)구현이 정의되고> 1 일 수 있으므로 부분 쓰기가 발생할 수 있습니다. 캐시 일관성 문제도 있습니다.
Snps


1
이 표준을 참고 : C ++ 14이 필요합니다 chrono_literals 컴파일
파트 리 지오 베르 토니

6

쉬운 해결책은 스레드가 정기적으로 true로 설정하고 상태를 알고 자하는 스레드가이를 확인하고 false로 설정하는 부울 변수를 갖는 것입니다. 오랫동안 변수가 거짓이면 스레드는 더 이상 활성 상태로 간주되지 않습니다.

보다 스레드로부터 안전한 방법은 자식 스레드에 의해 증가되는 카운터를 갖는 것이며, 주 스레드는 카운터를 저장된 값과 비교하고 너무 오랜 시간이 지난 후에도 동일하면 자식 스레드가 활성 상태가 아닌 것으로 간주됩니다.

그러나 C ++ 11에서는 실제로 중단 된 스레드를 죽이거나 제거 할 수있는 방법이 없습니다.

편집 스레드가 완전히 종료되었는지 확인하는 방법 : 기본적으로 첫 번째 단락에서 설명한 것과 동일한 기술입니다. 부울 변수를 false로 초기화하십시오. 자식 스레드가 마지막으로 수행하는 작업은 true로 설정하는 것입니다. 그런 다음 주 스레드는 해당 변수를 확인할 수 있으며 참이면 많은 (있는 경우) 차단없이 자식 스레드에서 조인을 수행합니다.

Edit2 스레드가 예외로 인해 종료되면 두 개의 스레드 "메인"함수가 있습니다. 첫 번째 스레드에는 두 번째 "실제"메인 스레드 함수를 호출 하는 try- catch가 있습니다. 이 첫 번째 주 함수는 "have_exited"변수를 설정합니다. 이 같은:

bool thread_done = false;

void *thread_function(void *arg)
{
    void *res = nullptr;

    try
    {
        res = real_thread_function(arg);
    }
    catch (...)
    {
    }

    thread_done = true;

    return res;
}

1
이것이 OP의 "실행 중"정의 인 경우.
CashCow

당신이 나를 오해했을 수도 있습니다. 스레드가 깨끗하게 종료되었는지 확인하고 싶습니다. 불분명 한 표현에 대해 죄송합니다.
kispaljr

7
다른 스레드가 읽고 쓰는 thread_done경우이 코드는 메모리 장벽없이 손상됩니다. std::atomic<bool>대신 사용하십시오 .
ildjarn

1
여러 작업자 스레드를 언급 한 것이 아니라 단일 작업자 스레드를 쓰는 bool동안 주 스레드에서 읽는 동안 메모리 장벽 이 필요 합니다.
ildjarn

3
여기에서 왜 a 가 필요한지 토론하려면 이 질문 을 확인 std::atomic<bool>하십시오.
Robert Rüger 2013 년

3

이 간단한 메커니즘은 조인 메서드에서 차단하지 않고 스레드 종료를 감지하는 데 사용할 수 있습니다.

std::thread thread([&thread]() {
    sleep(3);
    thread.detach();
});

while(thread.joinable())
    sleep(1);

2
스레드를 분리하는 것은 결국 원하는 join()것이 아닙니다 joinable(). 그렇지 않은 경우 스레드가 속성 을 잃을 때까지 기다리지 않는 일부 스레드에서 호출해야 합니다. 그렇지 않으면 끝없이 반복됩니다 (즉 joinable(), 스레드가 실제로 join())까지 완성 된 에드하지
니클라스 R

joinable은 스레드가 스레드 핸들을 잡고 있음을 의미합니다. 스레드가 완료되면 여전히 결합 할 수 있습니다. 스레드의 끝을 기다리지 않고 확인해야하는 경우 여기에 해결책이 있습니다. 단지 몇 줄의 코드입니다. 왜 먼저 시도하지 않았습니까?
Evgeny Karpov

나는 그랬고 내가 말하려는 요점은 thread.detach()부품 을 제거하면 위의 프로그램이 절대 종료되지 않는다는 것입니다.
Niklas R

예, 그렇지 않습니다. 그것이 결국 분리라고 부르는 이유입니다.
Evgeny Karpov

1
이 분리 호출 방법은 뮤텍스 및 기타 더 복잡한 솔루션이 필요하지 않습니다. 나는 그것을 사용하고 작동합니다! 답변 해주셔서 감사합니다.
sep.

1

실행중인 스레드와 호출 스레드가 모두 액세스 할 수있는 뮤텍스를 만듭니다. 실행중인 스레드가 시작되면 뮤텍스를 잠그고 종료하면 뮤텍스를 잠금 해제합니다. 스레드가 여전히 실행 중인지 확인하기 위해 호출 스레드는 mutex.try_lock ()을 호출합니다. 그 반환 값은 스레드의 상태입니다. (try_lock이 작동하면 뮤텍스를 잠금 해제해야합니다.)

이것에 대한 한 가지 작은 문제, mutex.try_lock ()은 스레드가 생성 된 시간과 뮤텍스를 잠글 때 사이에 false를 반환하지만 약간 더 복잡한 방법을 사용하여 피할 수 있습니다.


-1 std::mutex이러한 종류의 시그널링 에는 사용하지 않아야합니다 (대부분 뮤텍스가 일반적으로 구현되는 이유 때문에). 은 atomic_flag적은 오버 헤드 방식으로이 경우에는 그냥 잘 작동합니다. A std::future는 의도를 더 명확하게 표현하므로 더 좋을 수 있습니다. 또한, 그것은 try_lock가짜로 실패 할 수 있으므로 반환이 반드시 스레드의 상태가되는 것은 아닙니다 (이 특별한 경우에는 크게 해를 끼치지는 않을 것입니다).
ComicSansMS

1

스레드의 ID가 기본 생성 된 std :: thread :: id ()와 다른지 항상 확인할 수 있습니다. 실행중인 스레드에는 항상 정품 관련 ID가 있습니다. 너무 많은 멋진 물건을 피하십시오 :)


0

확실히 뮤텍스 래핑 변수가로 초기화되어 false스레드 true가 종료하기 전에 마지막으로 설정하는 것으로 설정됩니다 . 그게 당신의 필요에 충분히 원자 적입니까?


1
어쨌든 뮤텍스를 사용하면 내 솔루션 (부울이없는 뮤텍스 만 사용)이 더 우아하다고 느낍니다. 스레드로부터 안전한 부울을 절대적으로 사용하려면 std :: atomic <bool> 대신 사용하는 것이 좋습니다. 대부분의 구현에서 잠금이 없습니다.
kispaljr

왜 잠그나요? 하나의 스레드는 읽기만하고 하나는 쓰기 만합니다. 그리고 단어 크기 쓰기는 어떤 경우에도 IIRC 원자 적입니다.
Xeo

1
@Xeo : 쓰기는 원자적일 수 있지만 다른 스레드 (다른 CPU에서 실행될 수 있음)에서 작성된 값을 볼 것으로 예상되는 경우에는 여전히 메모리 장벽이 필요합니다. std::atomic<bool>당신을 위해 이것을 처리하기 때문에 이것이 진정한 대답 IMO입니다.
ildjarn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.