2012-11-08 84 views
4

第一次在這裏發佈,但我已經徹底搜索這個問題的解決方案並且沒有解決方案。我有一個類,基本上使用一個靜態範圍的線程池來計算矩陣的條目。當需要進行新的計算時,靜態條件變量表示這一點。當程序結束時,一個靜態布爾標誌被改變,主線程在退出之前調用join_all。問題是,當我從int main()返回時,程序看起來在銷燬靜態變量期間掛起。C++/boost :: thread程序在join_all後掛起並從主返回

下面是執行計算的類粗糙源碼:

class FunctionCalculator 
{ 
    public: 
     static void createWorkers(); 
     static void destroyWorkers(); 
     static void calcFunction(); 

    private: 
     static void run(); 

     static boost::thread_group workers_; 
     static boost::mutex theLock_; 

     static int curIndex_; 
     static unsigned int numCalcsComplete_; 

     static boost::condition_variable stateChange_; 
     static boost::condition_variable calculationFinished_; 

     static bool finished_; 

     static struct SharedCalcData { // some vars } calcData_; 
}; 

// static member definitions 
int FunctionCalculator::curIndex_; 
unsigned int FunctionCalculator::numCalcsComplete_; 
boost::mutex FunctionCalculator::theLock_; 
boost::condition_variable FunctionCalculator::stateChange_; 
boost::condition_variable FunctionCalculator::calculationFinished_; 
boost::thread_group FunctionCalculator::workers_; 
bool FunctionCalculator::finished_; 
FunctionCalculator::SharedCalcData FunctionCalculator::calcData_; 

void FunctionCalculator::createWorkers() 
{ 
    finished_ = false; 
    curIndex_ = -1; 

    for(unsigned int i = 0; i < 4; i++) 
     workers_.create_thread(boost::bind(&FunctionCalculator::run)); 
} 

void FunctionCalculator::destroyWorkers() 
{ 
    { 
     boost::mutex::scoped_lock lock(theLock_); 

     finished_ = true; 
     curIndex_ = 0; 

     stateChange_.notify_all(); 
    } 

    workers_.join_all(); 
} 

void FunctionCalculator::run() 
{ 
    unsigned int i = 0; // the column of the matrix to fill in 
    while (true) 
    { 
     { 
      boost::mutex::scoped_lock lock(theLock_); 

      // block if the calculation is finished until there's a new calculation 
      while (curIndex_ < 0) 
       stateChange_.wait(lock); 

      // check if it's time for threads to die 
      if (finished_) 
       break; 

      // get the next index to process 
      i = (unsigned int)curIndex_++; 

      // signal all threads to block if this is the last thread in the calculation 
      if (i == 49) 
       curIndex_ = -1; 
     } 

     // perform calculation/fill in matrix 

     { 
      boost::mutex::scoped_lock lock(theLock_); 

      ++numCalcsComplete_; 

      // wake up the main thread if this was the last thread in the calculation 
      if (numCalcsComplete_ == 50) 
       calculationFinished_.notify_one(); 
     } 
    } 
} 

void FunctionCalculator::calcFunction() 
{ 
    // assign calcData_ 

    { 
     boost::mutex::scoped_lock lock(theLock_); 

     curIndex_   = 0; 
     numCalcsComplete_ = 0; 

     stateChange_.notify_all(); 

     while (curIndex_ >= 0) 
      calculationFinished_.wait(lock); 
    } 
} 

這裏是主要方法的一些粗糙代碼。它實際上是由主調用createWorkers()和calcFunction()實際上是由GNU科學圖書館(我使用這個原因靜態成員)被稱爲創建的對象,但這個想法是這樣的:

int main(int argc, char* argv[]) 
{ 
    FunctionCalculator fc; 

    FunctionCalculator::createWorkers(); 

    for (int i = 0; i < 10; i++) 
     fc.calcFunction(); 

    FunctionCalculator::destroyWorkers(); 

    return EXIT_SUCCESS; 
} 

呼叫後到EXIT_SUCCESS,程序掛起,但我已經驗證了FunctionCalculator中的四個線程在調用destroyWorkers()後已經完成了run()方法。既然程序達到了從main返回的程度,我的理論是,當靜態boost庫變量最終被銷燬時,問題就會發生。任何人都可以看到問題嗎?

+0

你可以附加一個調試器並在程序低於'main()'時獲得堆棧跟蹤嗎? –

+0

除去所有靜態信息,以便您有機會看到發生錯誤的位置? –

+2

您的程序在Boost主幹上運行良好。 –

回答

-1

根據您的編譯器的優化程度以下代碼:

while (curIndex_ < 0) 
      stateChange_.wait(lock); 

可以解釋爲

while (true) 
      stateChange_.wait(lock); 

,因爲變量curIndex_沒有這個while循環中改變。這可能會導致你提到的僵局。您可以將curIndex_聲明爲volatile,以強制編譯器不優化對此變量的訪問。

+1

不,'volatile'不適用於多線程,它應該是一個原子變量。請參閱http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484 –

+0

是的,如果您使用支持它的編譯器,我目前沒有:) – Mert

+1

如果您使用Boost和您的編譯器不支持原子,查看Boost.Atomic(http://www.boost.org/doc/libs/1_53_0/doc/html/atomic.html) – Ferruccio

相關問題