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() を呼び出す main によって作成されたオブジェクトであり、 calcFunction() は実際には Gnu Scientific Library によって呼び出されます (この理由で静的メンバーを使用します) が、アイデアは次のとおりです。

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 を呼び出した後、プログラムはハングしますが、関数電卓の 4 つのスレッドが destroyWorkers() が呼び出された後に run() メソッドを終了したことを確認しました。プログラムは main からの戻りまで到達するため、静的ブースト ライブラリ変数が最後に破棄されるときに問題が発生するというのが私の理論です。誰でも問題を見ることができますか?

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 に答える