2017-12-17 20 views
1

아래 코드에서 동일한 예외를 다시 throw 한 후에 예외를 catch하려고 시도하지만 동일한 결과를 얻을 수 없습니다. 나는 current_exception()을 통해 현재 teptr 상태를 보존했기 때문에 무엇이 잘못되었는지 확신하지 못한다. 스레드가 연속 루프에서 실행되므로 해당 값이 큰 2에 도달하면 catch 블록이 실행되고 제어가 루프에서 벗어나지 만 예상대로 계속 첫 번째 시도에서 다른 catch 블록에 도달 할 수 없습니다.스레드에서 예외를 throw하는 것이 예상 결과를 제공하지 않습니다.

#include <boost/thread.hpp> 
#include <boost/thread/scoped_thread.hpp> 
#include <boost/chrono.hpp> 
#include <iostream> 
#include <boost/exception/all.hpp> 
#include <exception> 
using namespace std; 
boost::exception_ptr teptr; 

class myexception : public exception 
{ 
    virtual const char* what() const throw() 
    { 
     return "My exception happened"; 
    } 
} myex; 

class ABC 
{ 
public: 
    void start(); 

}; 

void ABC::start() 
{ 
    int i = 0; 
    cout << "running the thread" << std::endl; 

    while (1) 
    { 
     try 
     { 
      std::cout << "value of " << i << '\n'; 

      if (i > 2) 
      { 
       throw boost::enable_current_exception(myex); 
      } 
      i++; 
     } 
     catch (exception& e) 
     { 
      cout << "actual exception is" << e.what() << '\n'; 
      teptr = boost::current_exception(); 
      break; 
      //throw myex; 
     } 
    } 
} 

int main() 
{ 
    ABC abc; 
    boost::thread thread_point; 

    while (1) 
    { 
     boost::thread thread_point; 
     thread_point = boost::thread(&ABC::start, abc); 

     if (teptr) { 

      try { 
       boost::rethrow_exception(teptr); 
      } 
      catch (const std::exception &ex) 
      { 
       std::cerr << "Thread exited with exception: " << ex.what() << "\n"; 
       exit(0); 
      } 
     } 
    } 
} 
+0

당신은'teptr'에 할당합니다. 어딘가에서'join '을 할 의향이 있습니까? –

+0

거기에 가입 할 필요는 없습니다. – user2997518

+0

당신은 어떻게 생각하니? –

답변

4

프로그램은 동기없이 여러 스레드에서 변수 teptr (및 myex)을 동시에 액세스합니다. 동작은 정의되지 않습니다.

더 나쁜 것은 thread_point을 섀도 잉하고 결합되지 않은 많은 스레드를 만드는 것입니다. 말 그대로 무제한의 쓰레드가 같은 글로벌 데이터를 공유하고 있습니다.

실제로 어디서나 값이나 예외를 반환 할 수있는 future을 찾고 있다고 가정합니다. 모든 예외 처리 마법은 당신을 위해 수행됩니다

Live On Coliru

#include <thread> 
#include <future> 
#include <iostream> 
#include <sstream> 

struct ABC { 
    int task(int until) { 
     for (int i = 0; i<10; ++i) { 
      if (i > until) { 
       std::ostringstream oss; 
       oss << "My exception happened in thread " << std::this_thread::get_id() << " at i=" << i; 
       throw std::runtime_error(oss.str()); 
      } 
     } 

     return 42; 
    } 
}; 

int main() { 
    for (int runs = 0; runs < 10; ++runs) { 
     ABC abc; 
     std::future<int> result = std::async(&ABC::task, &abc, rand()%20); 

     try { 
      std::cout << "Task returned " << result.get() << "\n"; 
     } catch (const std::exception &ex) { 
      std::cout << "Task exited with exception: " << ex.what() << "\n"; 
      std::cerr << "Thread exited with exception: " << ex.what() << "\n"; 
     } 
    } 
} 

인쇄 (예를)

(teptr가)`하기 전에 실행하면`중지 거기에 아무것도 여기
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=4 
Thread exited with exception: My exception happened in thread 140288972076800 at i=4 
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=7 
Thread exited with exception: My exception happened in thread 140288972076800 at i=7 
Task returned 42 
Task returned 42 
Task returned 42 
Task returned 42 
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=7 
Thread exited with exception: My exception happened in thread 140288972076800 at i=7 
Task returned 42 
Task returned 42 
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=2 
Thread exited with exception: My exception happened in thread 140288972076800 at i=2 
+0

Boost 사용을 주장하는 경우에 Boost [Live On Coliru] (http://coliru.stacked-crooked.com/a/3be82d5daaa6d1fc)를 사용하는 C++ 03 버전 – sehe

+0

감사합니다. 아래 링크에서 구현을 업데이트했습니다. http://coliru.stacked-crooked.com/a/21d556a378ccf6eb – user2997518

+0

보통 스레드 내부에서 제 3 자 라이브러리에서 발생시킨 예외를 잡아 내고 다시 catch 블록에서 동일한 블록을 재실행해야 외부와 전파 될 수 있습니다. 인터페이스. 이것을보고 제안 해주십시오. 다음은 오류입니다. 'boost :: exception_detail :: clone_impl 인스턴스를 throw 한 후에 .terminate가 호출됩니다. http://coliru.stacked-crooked.com/a/21d556a378ccf6eb – user2997518

0

업데이트 내 대답은 결핍과 오류, sehe의 의견을 참조하십시오.

최종 목표는 무엇인지 모르겠지만 스레드에서 던지기를 처리하는 방법을 알아 내려고합니다. 예, Boost Exception을 사용하여 컴파일러가 스레드간에 던지지 못하게 할 수 있습니다.

#include <boost/thread.hpp> 
#include <boost/thread/scoped_thread.hpp> 
#include <boost/chrono.hpp> 
#include <iostream> 
#include <boost/exception/all.hpp> 
#include <exception> 

boost::exception_ptr teptr; 
class myexception: public std::exception 
{ 
    virtual const char* what() const throw() 
    { 
     return "My exception happened"; 
    } 
} myex; 


class ABCc 
{ 
public: 
    void start(); 
}; 

void ABCc::start() 
{ 
    int i=0; 
    std::cout<<"running the thread"<<std::endl; 

    while (1) 
    { 
     try 
     { 
      std::cout << "value of "<<i << '\n'; 

      if(i>2) 
      { 
       throw boost::enable_current_exception(myex); 
      } 
      i++; 
     } 
     catch (std::exception& e) 
     { 
      std::cout << "actual exception is"<<e.what() << '\n'; 
      teptr=boost::current_exception(); 
      break; 
      // where were you going here??????? 
      //throw myex; 
     } 
    } 
} 

int main() 
{ 
    ABCc abc; 
    boost::thread thread_point; 
    thread_point = boost::thread(&ABCc::start,abc); 
    while(1) 
    { 
     if (teptr) { 
      try { 
       boost::rethrow_exception(teptr); 
      } 
      catch(const std::exception &ex) { 
       std::cerr << "Thread may have exited; exception thrown: " << ex.what() << "\n"; 
       break; 
      } 
     } 
    } 
    std::cout << "exception should have been caught" << std::endl; 
    return 0; 
} 

주를 던지거나 캐치 할 필요가 없습니다. 루프 내에서 boost :: thread를 사용하여 다중 쓰레드를 생성하는 것은 의도였습니까?

+0

이 코드에는 여전히 경쟁 조건이 있습니다. 데이터 경주는 실제로 [정의되지 않은 동작] (https://en.wikipedia.org/wiki/Undefined_behavior)입니다. while 루프는 무한하며 'teptr'에서 변경을 감지하지 못합니다 (왜 그렇습니까? '휘발성'이 아니라 메모리 장벽이 없다. 컴파일러는 단일로드 후에 값을 구해서 다른로드를 생성 할 필요가 없다.) – sehe