2012-05-25 2 views
4

다음은 예외/exception_ptr 내부 상태가 파괴되는 동안 경쟁 조건으로 인해 1 스레드에서 다른 스레드로 boost :: exception 오브젝트를 복사/전송하는 샘플 코드입니다. 나는 그것을 해결하는 가장 좋은 방법은 무엇인지 모르겠습니다.부스트간에 복사 boost :: exception이 발생했습니다.

사용 된 부스트 버전은 1.42이고 플랫폼은 듀얼 코어 Intel m/c에서 실행되는 우분투입니다. 컴파일러는 gcc 4.4.3이었다.

#include <iostream> 

#include <boost/exception/all.hpp> 
#include <boost/thread.hpp> 

struct Exception 
    : public virtual std::exception 
    , public virtual boost::exception 
{ 
}; 

struct MyException : public virtual Exception {}; 

struct MyTag {}; 

typedef boost::error_info<MyTag, std::string> MyError; 

struct Test 
{ 
    Test() 
    { 
     _t.reset(new boost::thread(boost::bind(&Test::executor, this))); 
    } 

    ~Test() 
    { 
     _t->join(); 
    } 

    void executor() 
    { 
     std::cerr << "executor: starting ...\n"; 
     for (;;) 
     { 
      boost::unique_lock<boost::mutex> lk(_mx); 
      while(_q.empty()) 
      { 
       _cv.wait(lk); 
      } 
      { 
       boost::shared_ptr<boost::promise<int> > pt = _q.front(); 
       _q.pop_front(); 
       lk.unlock(); 
       pt->set_exception(boost::copy_exception(MyException() << MyError("test"))); 
      } 
     } 
    } 

    void run_impl() 
    { 
     try 
     { 
      boost::shared_ptr< boost::promise<int> > pm(new boost::promise<int>()); 

      boost::unique_future<int> fu = pm->get_future(); 
      { 
       boost::unique_lock<boost::mutex> lk(_mx); 
       _q.push_back(pm); 
       pm.reset(); 
      } 
      _cv.notify_one(); 

      fu.get(); 
      assert(false); 
     } 
     catch (const MyException& e) 
     { 
      throw; 
     } 
     catch (const boost::exception&) 
     { 
      assert(false); 
     } 
     catch (...) 
     { 
      assert(false); 
     } 
    } 

    void run() 
    { 
     std::cerr << "run: starting ...\n"; 
     for (;;) 
     { 
      try 
      { 
       run_impl(); 
      } 
      catch (...) 
      { 
      } 
     } 
    } 

private: 

    boost::mutex _mx; 
    std::list< boost::shared_ptr< boost::promise<int> > > _q; 
    boost::shared_ptr<boost::thread> _t; 
    boost::condition_variable_any _cv; 
}; 

int main() 
{ 
    Test test; 
    test.run(); 
} 

/* 
#0 0x080526bd in boost::exception_detail::refcount_ptr<boost::exception_detail::error_info_container>::release (this=0x806e26c) at /boost_1_42_0/boost/exception/exception.hpp:79    
#1 0x0804f7c5 in ~refcount_ptr (this=0x806e26c, __in_chrg=<value optimized out>) at /boost_1_42_0/boost/exception/exception.hpp:34               
#2 0x0804bb61 in ~exception (this=0x806e268, __in_chrg=<value optimized out>) at /boost_1_42_0/boost/exception/exception.hpp:254                
#3 0x0805579a in ~clone_impl (this=0x806e260, __in_chrg=<value optimized out>, __vtt_parm=<value optimized out>) at /boost_1_42_0/boost/exception/exception.hpp:391       
#4 0x001ff633 in ??() from /usr/lib/libstdc++.so.6                                       
#5 0x0027233d in _Unwind_DeleteException() from /lib/libgcc_s.so.1                                   
#6 0x001fe110 in __cxa_end_catch() from /usr/lib/libstdc++.so.6                                    
#7 0x0804f7a4 in Test::run (this=0xbffff74c) at ex_org.cpp:89                                     
#8 0x0804b869 in main() at ex_org.cpp:106 
*/ 
+0

등이

void executor() { std::cerr << "executor: starting ...\n"; for (;;) { _cv.wait(lk); boost::unique_lock<boost::mutex> lk(_mx); __sync_synchronize(); // Tells the compiler to prevent optimizations if (!_q.empty()) { boost::shared_ptr<boost::promise<int> > pt = _q.front(); _q.pop_front(); pt->set_exception(boost::copy_exception(MyException() << MyError("test"))); } } } 

처럼 쓴다 무엇 참조보다는 비 참조를 잡기는 어떻습니까? 그래서 로컬 사본이 생성됩니다. – Nick

+0

도움이되지 않지만 여전히 동일한 충돌로 끝납니다. – Harish

+0

g ++ 4.7.0을 사용하여 이것을 재현하려고 시도했지만 1.49가 향상되었지만 예제가 Intel i5의 아치 리눅스 3.4.0에서 완벽하게 작동합니다. – nijansen

답변

0

내가 부스트 전문가가 아니에요하지만 난 어떤 인종 문제를 발견, 그것은 디버그 모드에서 확인을 실행 하는가? 집행자를 들어

나뿐만 아니라

void run_impl() 
{ 
    try 
    { 
     boost::shared_ptr< boost::promise<int> > pm(new boost::promise<int>()); 

     boost::unique_future<int> fu = pm->get_future(); 

     { 
      boost::unique_lock<boost::mutex> lk(_mx); 

      // prevent the compiler from mixing above and below code 
      __sync_synchronize(); 

      _q.push_back(pm); 
      pm.reset(); 
     } 

     _cv.notify_one(); 

     // This one is the paranoïd's one ;), one must check without ! 
     __sync_synchronize(); 

     { 
      // since fu must holds an internal reference pm being currently 
      // changed by the other thread ! 
      boost::unique_lock<boost::mutex> lk(_mx); 

      // Then you are assured that everything is coherent at this point 
      // the stack frame holding the exception stuffs won't be corrupted 

      fu.get(); 
     } 

     assert(false); 
    } 
관련 문제