C ++ / boost :: thread program freezes after join_all and returns from Main

The initial publication is here, but I am carefully looking for a solution to this problem and have no solution. I have a class that computes records for a matrix, using basically a pool of streams with static coverage. When you need to perform a new calculation, this is signaled by a static condition variable. And when the program ends, the static logic flag changes, and the main thread calls join_all before exiting. The problem is that when I return from int main (), the program hangs, it would seem, during the destruction of static variables.

Here is the rough source code for the class that does the calculation:

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 a new calculation while ( curIndex_ < 0 ) stateChange_.wait( lock ); // check if it 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 ); } } 

Here is an approximate code for the main method. In fact, the object created mainly calls the createWorkers () and calcFunction () calls, actually called by the Gnu Science Library (I use static members for this), but the idea is this:

 int main( int argc, char* argv[] ) { FunctionCalculator fc; FunctionCalculator::createWorkers(); for ( int i = 0; i < 10; i++ ) fc.calcFunction(); FunctionCalculator::destroyWorkers(); return EXIT_SUCCESS; } 

After calling EXIT_SUCCESS, the program freezes, but I confirmed that four threads in the FunctionCalculator completed the run () method after calling destroyWorkers (). Since the program comes to a return from the main one, my theory is that the problem arises when at the end the variables of the static acceleration library are destroyed. Can anyone see the problem?

+4
source share
1 answer

Depending on the optimization level of your compiler, the following code:

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

can be interpreted as

 while ( true ) stateChange_.wait( lock ); 

because the variable curIndex_ does not change inside this while loop. This may lead to you mentioning a dead end. You can declare curIndex_ as volatile to prevent the compiler from optimizing access to this variable.

-1
source

Source: https://habr.com/ru/post/1444864/


All Articles