2

私はかなり厄介な問題に苦しんでいます。エンティティマネージャーが更新ループ内のエンティティのマップを反復処理すると、セグメンテーション違反が発生することがあります。奇妙なことに、これは常に発生するわけではありません。ロード時にクラッシュすることもあれば、セグメンテーション違反が発生する前にアプリの状態を数回切り替える(およびエンティティのロードとアンロードを何度も行う)ことがある場合もあります。また、デバッグモードでより多くのsegfaultが発生するようです。私のエンティティは、BehaviorクラスとDrawableクラスへのポインタで構成されています。

セグメンテーション違反後の私のコールスタック:

#0 6FCB4986 libstdc++-6!_ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base() (C:\MinGW\bin\libstdc++-6.dll:??)
#1 0040A1D7 std::_Rb_tree_iterator<std::pair<unsigned int const, Entity*> >::operator++(this=0x28fe94) (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_tree.h:196)
#2 00401F55 EntityManager::onLoop(this=0x417238) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\engine\EntityManager.cpp:75)
#3 00401640 App::onLoop(this=0x417040) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\engine\App.cpp:38)
#4 0040160C App::execute(this=0x417040) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\engine\App.cpp:30)
#5 00403BD7 main(argc=1, argv=0x642908) (C:\Users\Nelarius\Documents\Kurssit\Miinaharava\src\main.cpp:15)

これが私の更新ループです:

void EntityManager::onLoop()
{
    std::map<const unsigned int, Entity*>::iterator it;

    for (it = _gameObjects.begin(); it != _gameObjects.end(); it++)
    {
        Behavior* behavior = it->second->getBehavior();
        if (behavior)
        {
            behavior->update();
        }
    }
}

私はでセグメンテーション違反を取得します

for (it = _gameObjects.begin(); it != _gameObjects.end(); it++)

ちなみに、マルチスレッドを使用していないときにスレッドが2つあるのは正常ですか?デバッグウィンドウを調べていたところCode::Blocks、スレッドウォッチウィンドウに2つのスレッドがあることがわかりました(ただし、そのうちの1つだけがアクティブでした)。

4

2 に答える 2

2

多くの場合、この種のことはbehavior->update()、ネストされた関数呼び出しのシーケンスを介して、_gameObjects変更されるコンテナーで結果を出すことができるようになります(たとえば、ゲームオブジェクト内で検出された条件によって、ゲームオブジェクトが作成または削除された場合など)理由)。

から要素を削除すると、イテレータが無効になり、ループが中断するmap可能性があり、このような「カーネル」コードで見つけるのが難しい場合があります。

一般的な解決策は、ループのゲームオブジェクトのリストをコピーすることです。もちろん、オブジェクト自体をコピーすることはありませんが、更新の実行中にオブジェクトのリストが変更されないように保護しています。

また、スケジューリングの観点からも「公平」です。不満を持った自己複製ゲームオブジェクトによってDDoS攻撃が開始される可能性を本質的に回避できます。:)

于 2013-01-28T13:45:55.030 に答える
0

非ローカルデータを反復処理してから、非ローカル関数を呼び出しています。

ローカルマップを作成します。 swapクラスはそれにマップします。そのローカルマップを繰り返し処理します。反復が行われた後、クラスマップが変更されていないことを表明します(クラスマップからのものを削除するすべての試みが成功することも表明する必要があります)。

次に、ローカルマップをクラスのマップに戻します。

これにより、設計の誤りが原因でクラッシュが発生したかどうかがわかります。上記のコードから遠く離れた無害なコード変更により、上記のような問題が発生する可能性があるため、これによってアサートが生成されない場合でも、設計には問題が残ります。コードの正確性が非局所的であると問題が発生します。アサートによるコードの非局所性は、十分なテストを行うことで許容できます。

一般的なコールバックの問題では、登録されたコールバックであることの意味について妥協する必要があり、マルチスレッドコードと同様の方法で問題について考える必要があります。妥協したくない場合は、コードの複雑度が非常に高くなる可能性があります。物事を単純化するためにスマートポインタを使用することをお勧めします。

于 2013-01-28T13:37:40.260 に答える