활성 예외없이 호출 된 C ++ 종료


94

스레딩에 C ++ 오류가 발생합니다.

terminate called without an active exception
Aborted

다음은 코드입니다.

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template<typename TYPE>
class blocking_stream
{
public:
    blocking_stream(size_t max_buffer_size_)
        :   max_buffer_size(max_buffer_size_)   
    {
    }

    //PUSH data into the buffer
    blocking_stream &operator<<(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx); 
        while(buffer.size()>=max_buffer_size)
            stop_if_full.wait(mtx_lock);

        buffer.push(std::move(other));

        mtx_lock.unlock();
        stop_if_empty.notify_one();
        return *this;
    }
    //POP data out of the buffer 
    blocking_stream &operator>>(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx);
        while(buffer.empty())
            stop_if_empty.wait(mtx_lock);

        other.swap(buffer.front()); 
        buffer.pop();

        mtx_lock.unlock();
        stop_if_full.notify_one();
        return *this;
    }

private:
    size_t max_buffer_size;
    std::queue<TYPE> buffer;
    std::mutex mtx;
    std::condition_variable stop_if_empty,
                            stop_if_full;
    bool eof;   
};

이 예제를 중심으로 코드를 모델링했습니다. http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

내가 뭘 잘못하고 있고 어떻게 오류를 수정합니까?


9
당신이 있습니까 join메인 프로그램의 모든 스레드를 보내고?
Kerrek SB 2011 년

나머지 코드를 보여주세요.
Matt

2
@ Kerek ah ha 이것은 문제를 해결했지만, 작업자가 완료되기 전에 메인 스레드가 종료되지 않았 음을 확신하지만 왜 그런지 모르겠습니다. 또한 내 잠금 알고리즘이 올바르게 표시됩니까?
111111 2011 년

문제를 재현하는 컴파일 가능한 코드를 참조하십시오.
Martin York

3
이 경우 런타임이 더 나은 진단을 내릴 수 있습니까?
Nemo 2011

답변:


127

스레드 개체가 범위를 벗어나 결합 가능한 상태가되면 프로그램이 종료됩니다. 표준위원회에는 조인 가능한 스레드의 소멸자에 대한 두 가지 다른 옵션이 있습니다. 조용히 조인 할 수 있지만 스레드가 멈춘 경우 조인이 반환되지 않을 수 있습니다. 또는 스레드를 분리 할 수 ​​있습니다 (분리 된 스레드는 결합 할 수 없음). 그러나 분리 된 스레드는 프로그램이 끝날 때까지 살아남아 리소스 해제를 망칠 수 있기 때문에 매우 까다 롭습니다. 따라서 프로그램을 종료하지 않으려면 모든 스레드를 조인 (또는 분리)해야합니다.


1
"스레드 객체가 범위를 벗어나 결합 가능한 상태이면 프로그램이 종료됩니다."이것에 대한 간단하고 재현 가능한 예제를 제공 할 수 있습니까? OP의 예는 약간 복잡합니다.
Alec Jacobson

1
그리고 그 진술은이 답변과 모순되는 것 같습니다 : stackoverflow.com/a/3970921/148668
Alec Jacobson

5
@mangledorf : 그들이 말하고 있지만 boost :: thread는 std :: thread에 대해 이야기하고 있습니다. 이 두 가지는 파괴 행동이 다릅니다. 이것은위원회의 의식적인 결정이었습니다.
Bartosz Milewski 2012 년

이 문제가 발생하면 std::async어떻게합니까? 생성 될 수있는 스레드를 어떻게 결합 / 분리합니까? 때문에, 충분히 될 결과 미래에 기다리고 아닌 것 같아 이 말한다 스레드가, 미래의 대기 ( "잠재적으로 스레드 풀에서 할"수있는 정말 수영장에서 스레드를 종료 암시 (그 같으면하지 않습니다) 건전한 스레드 풀에는 어쨌든 의미가 없습니다).
Jason C

2
C ++ 20에서 업데이트 만하면 소멸자에서 std::jthread호출 .join()됩니다 (범위를 벗어남에 따라). RAII를 더 잘 따르기 때문에 개인적으로 더 좋아합니다.
pooya13

46

오류를 재현하는 방법 :

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  return 0;
}

컴파일 및 실행 :

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
terminate called without an active exception
Aborted (core dumped)

스레드를 결합하거나 분리하지 않았기 때문에 해당 오류가 발생합니다.

이를 고치는 한 가지 방법은 다음과 같이 스레드를 결합하는 것입니다.

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  t1.join();
  return 0;
}

그런 다음 컴파일하고 실행합니다.

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

다른 방법은 다음과 같이 분리하는 것입니다.

#include <iostream>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() 
{ 
     {

        std::thread t1(task1, "hello"); 
        t1.detach();

     } //thread handle is destroyed here, as goes out of scope!

     usleep(1000000); //wait so that hello can be printed.
}

컴파일 및 실행 :

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

C ++ 스레드 분리 및 C ++ 스레드 결합에 대해 읽어보십시오.


1
이 컨텍스트에서 usleep () 사용은 스레드가 분리되고 핸들이 파괴 된 경우에만 의미가 있습니다 (범위를 벗어남). 그래서 이것을 반영하기 위해 코드를 편집했습니다.
Nawaz 2015 년

17

Eric Leschinski와 Bartosz Milewski는 이미 대답을했습니다. 여기서는 좀 더 초보자 친화적 인 방식으로 표현하려고 노력할 것입니다.

스레드가 범위 내에서 시작되면 (스레드에서 자체적으로 실행 됨) 스레드가 범위를 벗어나기 전에 다음 중 하나가 발생하는지 명시 적으로 확인해야합니다.

  • 런타임은 스레드가 실행을 마친 후에 만 ​​범위를 종료합니다. 이것은 해당 스레드와 결합하여 달성됩니다. 언어에 유의하십시오. 해당 스레드와 결합하는 것은 외부 범위입니다.
  • 런타임은 스레드가 자체적으로 실행되도록 둡니다. 따라서 프로그램은이 스레드가 실행을 완료했는지 여부에 관계없이 범위를 종료합니다. 이 스레드는 자체적으로 실행되고 종료됩니다. 이것은 스레드를 분리하여 수행됩니다. 예를 들어 스레드가 해당 외부 범위의 변수를 참조하는 경우 문제가 발생할 수 있습니다.

스레드가 결합되거나 분리 될 때까지 실행이 잘 완료되었을 수 있습니다. 여전히 두 작업 중 하나를 명시 적으로 수행해야합니다.


1

프로그램이 죽는 한 스레드를 분리하거나 결합하지 않으면이 오류가 발생합니다. 스레드를 분리하고 결합하지 않고 스레드를 생성 한 후 무한 루프를 제공해야합니다.

int main(){

std::thread t(thread,1);

while(1){}

//t.detach();
return 0;}

잠자기 또는 루핑 후 스레드가 분리되거나 결합 될 수 있다는 것도 흥미 롭습니다. 또한 이렇게하면이 오류가 발생하지 않습니다.

아래 예제는 세 번째 스레드가 메인 다이 전에 자신의 작업을 수행 할 수 없음을 보여줍니다. 그러나이 오류는 코드의 어딘가에서 분리하는 한 발생할 수 없습니다. 세 번째 스레드는 8 초 동안 잠자지만 메인은 5 초 안에 죽습니다.

void thread(int n) {std::this_thread::sleep_for (std::chrono::seconds(n));}

int main() {
std::cout << "Start main\n";
std::thread t(thread,1);
std::thread t2(thread,3);
std::thread t3(thread,8);
sleep(5);

t.detach();
t2.detach();
t3.detach();
return 0;}

1

year, 스레드는 join ()이어야합니다. 메인 출구


1
이 답변은 아마도 다른 답변에 첨부 된 주석에 더 적합 할 것입니다. 그리고 Stack Overflow에 오신 것을 환영합니다!
Contango

0

먼저 스레드를 정의합니다. 그리고 스레드 소멸자를 호출하기 전에 join () 또는 detach ()를 호출하지 않으면 프로그램이 중단됩니다.

다음과 같이 먼저 join (완료 될 때까지 기다리기 위해)을 호출하거나 분리하지 않고 스레드 소멸자를 호출하면 std :: terminate를 즉시 호출하고 프로그램을 종료 할 수 있습니다.

소멸자에서 joinable () 스레드를 암시 적으로 분리하거나 조인하면 예외가 발생할 때만 발생하는 정확성 (분리의 경우) 또는 성능 (조인의 경우) 버그를 디버그하기가 어려울 수 있습니다. 따라서 프로그래머는 스레드가 여전히 결합 가능한 동안 소멸자가 실행되지 않도록해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.