4

第一次在这里发帖,但我已经彻底寻找这个问题的解决方案并且没有解决方案。我有一个类,它基本上使用静态范围的线程池来计算矩阵的条目。当需要进行新的计算时,静态条件变量会发出信号。当程序结束时,一个静态布尔标志被改变,主线程在退出前调用join_all。问题是当我从 int main() 返回时,程序在静态变量的销毁过程中似乎挂起。

这是执行计算的类的粗略源代码:

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 );
    }
}

这是主要方法的一些粗略代码。它实际上是由 main 创建的一个对象,它调用 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库变量最后被销毁时。任何人都可以看到问题吗?

4

1 回答 1

-1

根据您的编译器的优化级别,以下代码:

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

可以解释为

while ( true )
            stateChange_.wait( lock );

因为变量 curIndex_ 在这个 while 循环内没有改变。这可能会导致您提到的僵局。您可以将 curIndex_ 声明为 volatile 以强制编译器不优化对此变量的访问。

于 2013-04-22T19:56:37.617 回答