2013-07-03 100 views
1

我在Mac OS X 10.8上遇到一個奇怪的問題,使用XCode版本4.6.3(4H1503)和clang: Apple LLVM 4.2版(clang-425.0.28)(基於LLVM 3.2svn) 目標:x86_64-蘋果-darwin12.4.0 線程模型:POSIXC + + 11,std ::原子在clang 3.2和libC++中打破?

我創建了一個非常基本的thread_pool類,並想強調測試。

struct last_item_exception {}; 

    template<class Task> 
    struct thread_reclaimer 
    { 

     explicit 
     thread_reclaimer(impl::basic_task_queue<Task>& q)noexcept 
      : q_(q) 
     {} 

     void operator()() 
     { 
     try 
     { 
      while(true) 
      { 
      using namespace boost; 
      q_.wait_and_pop()(); 
      } 
     } 
     catch(last_item_exception) 
     { 
      TRACE_LOG << "caught last item exception"; 
     } 
     } 

    private: 
     impl::basic_task_queue<Task>& q_; 
    }; 



    template<class Task> 
    thread_reclaimer<Task> make_thread_reclaimer 
     (impl::basic_task_queue<Task>& queue)noexcept 
    { 
     return std::move(thread_reclaimer<Task>(queue)); 
    } 



    class thread_pool : public boost::noncopyable 
    { 
    typedef std::function<void()> task_type; 

    public: 
    explicit thread_pool(size_t number_of_threads) 
     : threads_created_() 
     , pool_() 
     , queue_() 
     , done_() 
    { 
     try 
     { 
     TRACE_LOG << "thread_pool: creating " <<number_of_threads << " threads"; 

     while(threads_created_<number_of_threads) 
     { 
      ++threads_created_; 
      pool_.create_thread(make_thread_reclaimer(queue_)); 
      TRACE_LOG << "thread_pool: created thread number: " 
        << threads_created_ 
      ; 
     } 
     TRACE_LOG << "thread_pool: all threads started"; 
     } 
     catch(...) 
     { 
     TRACE_LOG << "thread_pool: exception occured"; 
     finish_and_join_all(); 
     throw; 
     } 
     TRACE_LOG << "thread_pool: constructor finished"; 
    } 

    ~thread_pool() 
    { 
     finish_and_join_all(); 
    } 

    bool enqueue(task_type t) 
    { 
     if(done_) return false; 
     queue_.push(t, done_); 
     return !done_; //if done was set inbetween, no push occured! 
    } 

    void finish_and_join_all() 
    { 
     TRACE_LOG << "entered: finish_and_join_all & done is: " << done_; 
     if(done_) return; 
     done_ = true; 

     std::vector<task_type> cancellation_tasks 
     (threads_created_ 
     , [] 
      { 
      TRACE_LOG << "throwing last item exception"; 
      throw impl::last_item_exception(); 
      } 
     ) 
     ; 

     TRACE_LOG << "pushing last item to the queue"; 
     // atomically pushes all cancellation tasks 
     queue_.push(cancellation_tasks.begin(), cancellation_tasks.end()); 

     threads_created_ = 0; 

     TRACE_LOG << "waiting for all threads to finish"; 
     pool_.join_all(); 
    } 

    private: 
    size_t threads_created_; 
    boost::thread_group pool_; 
    //thread safe producer consumer queue, which uses condition variables for sync 
    impl::basic_task_queue<std::function<void()>> queue_; 
    std::atomic<bool> done_; 
    }; 

我的測試用例創建和破壞一個thread_pool對象與1個線程,即

for(size_t i = 0; i<100; ++i) 
    thread_pool pool(1); 

在第二循環迭代測試用例失敗,因爲done_在進入第一次finish_and_join_all()true。將std::atomic<bool>類型更改爲volatile bool可修復此問題。

測試的輸出是低於(這會導致condition_variable)失敗,因爲析構函數沒有等待所有線程完成:

Entering test case "ctor_stress_test" 
Assertion failed: (!ret), function ~condition_variable, file /usr/local/include/boost/thread/pthread/condition_variable_fwd.hpp, line 86. 
[2013-07-03 22:17:32.462265] [0x76f73180] [trace] thread_pool: creating 1 threads 
[2013-07-03 22:17:32.462303] [0x76f73180] [trace] thread_pool: created thread number: 1 
[2013-07-03 22:17:32.462312] [0x76f73180] [trace] thread_pool: all threads started 
[2013-07-03 22:17:32.462320] [0x76f73180] [trace] thread_pool: constructor finished 
[2013-07-03 22:17:32.462326] [0x76f73180] [trace] entered: finish_and_join_all & done is: false 
[2013-07-03 22:17:32.462332] [0x76f73180] [trace] pushing last item to the queue 
[2013-07-03 22:17:32.462357] [0x76f73180] [trace] waiting for all threads to finish 
[2013-07-03 22:17:32.462383] [0x10d9e000] [trace] throwing last item exception 
[2013-07-03 22:17:32.462404] [0x10d9e000] [trace] caught last item exception 
[2013-07-03 22:17:32.462434] [0x76f73180] [trace] executing ~basic_task_queue 
[2013-07-03 22:17:32.462447] [0x76f73180] [trace] thread_pool: creating 1 threads 
[2013-07-03 22:17:32.462474] [0x76f73180] [trace] thread_pool: created thread number: 1 
[2013-07-03 22:17:32.462480] [0x76f73180] [trace] thread_pool: all threads started 
[2013-07-03 22:17:32.462485] [0x76f73180] [trace] thread_pool: constructor finished 
[2013-07-03 22:17:32.462490] [0x76f73180] [trace] entered: finish_and_join_all & done is: true 
[2013-07-03 22:17:32.462495] [0x76f73180] [trace] executing ~basic_task_queue 
unknown location:0: fatal error in "ctor_stress_test": signal: SIGABRT (application abort requested) 
Leaving test case "ctor_stress_test"; testing time: 448mks 

這是性病::原子的預期行爲?

回答

4

原子對象初始化不是一個原子操作,此外,缺省初始化使其處於未初始化狀態(每§29.6.5[atomics.types.operations.req]/4)。

將其設置爲false使用原子,或至少在構造函數的開始定義明確的操作。

+0

謝謝!這真的解決了問題! – ovanes

相關問題