3

私は現在、c ++でマルチスレッド化する方法を学んでおり、そのためにboost::threadを使用しています。3 つのスレッドを実行する単純なゲームエンジンに使用しています。

スレッドのうちの 2 つは、基本的にボール、プレート、ボックスなどの PrimitiveObjects と呼ばれるものの内部に格納されている同じ変数の読み取りと書き込みを行っています。

しかし、私は本当にそれを機能させることができません.問題は、2つのスレッドが同時に同じメモリ位置にアクセスしようとしていることだと思います.ミューテックスロックを使用してこれを回避しようとしましたが、今のところ運がありません.これは機能します時々ですが、スパムすると、次の例外が発生します。

First-chance exception at 0x00cbfef9 in TTTTT.exe: 0xC0000005: Access violation reading location 0xdddddded.
Unhandled exception at 0x77d315de in TTTTT.exe: 0xC0000005: Access violation reading location 0xdddddded.

これらは、これに使用するオブジェクト内の関数であり、デバッガーもそれらを例外のせいにしています。

int PrimitiveObj::setPos(glm::vec3 in){
 boost::try_mutex::scoped_try_lock lock(myMutex);
  if ( lock)
  {
    position = in;
    return 1;
  }
  return 0;
}

glm::vec3 PrimitiveObj::getPos(){
 boost::try_mutex::scoped_try_lock lock(myMutex);
  if ( lock)
  {
   glm::vec3 curPos = position;
    return curPos;       
  }
  return glm::vec3(0,0,0);
}

これは、各プリミティブ obj を生成するために使用する関数です。(更新しました)

void generatePrimitive(){
PrimitiveObj *obj = new PrimitiveObj();
 obj->generate();
obj->setPos(getPlayerPos()+getEye()*4.0f);
prims.push_back(std::shared_ptr<PrimitiveObj>(obj));
}

プリントスクリーン

何か案は?編集: 新しい関数(2)、および myMutex はオブジェクトに対してプライベートになりました。プリミティブ オブジェクトの生成に使用する関数を追加しました。

エラー

編集:

これはスタックが指しているコードで、物理スレッド内で実行されています。

nr = getNumberOfPrimitives();

        double currentTime = glfwGetTime();
float deltaTime = float(currentTime - lastTime);
for(int r = 0; r < nr; r++) {




     prop = getPrimitive(r);
    glm::vec3 pos = prop->getPos()+glm::vec3(0,1.0f*Meter/deltaTime,0);

    prop->setPos(pos);

}

その他の関連コード:

int getNumberOfPrimitives(){
return prims.size();
}

PrimitiveObj * getPrimitive(int input) {
return prims[input];
}
4

1 に答える 1

2

最初のアイデアは、PrimitiveObjあなたが呼び出しているものは初期化されていないということです。次のようなものです:

PrimitiveObj* myObject;
myObject->getPos();

あなたが持っている例外は、初期化されていないポインター変数(開発者が初期化されていないと認識するように0xddddddddに設定されている)にアクセスし、0x10(= 16)バイトオフセットされたメンバーにアクセスすることです。

アクセス例外は、std:vector などのオブジェクトにアクセスし、同時に異なるスレッドから同じオブジェクトへの読み取りと書き込みを行った場合にも発生する可能性がありますが、その場所は多くの場合、0 で始まり、4 で割り切れる、よりランダムに見える数値です (例: 0x004da358)。

なぜそうなのですか?デバッグ コードは、認識可能な乱数 (0xdddddddd、0xbaadfood、0xfefefefe など) でメモリを初期化することがよくあります。変数が常に同じである場合 (たとえば、常に 0 に初期化される場合) はランダムです。開発者は、一部の変数が初期化されず、コードがリリースで動作しなくなるという事実を見逃す可能性があります。それらは認識しやすいので、番号が初期化されていないメモリからのものであることが一目でわかります。

以前は有効なポインタはヒープ アドレス空間を指していました。通常、このアドレス空間はやや低​​い数値から始まり、カウントアップします。複数のオブジェクトがヒープに割り当てられている場合、通常の操作では、各オブジェクトは 4、8、16 などで割り切れるメモリ アドレスに配置されます。オブジェクトのメンバーも 4 バイト境界に配置されるため、アクセス違反が発生します。以前は有効だったメモリにアクセスすると、多くの場合、0 で始まり 4 で割り切れるアドレスになります。

これらは経験則であり、正しい方向に向けるために使用することができ、使用する必要がありますが、厳密で迅速な規則ではないことに注意してください. また、デバッグ環境を指します。リリース環境には、どのアクセス違反が何によって引き起こされているかを推測するための非常に異なるルールがあります。

于 2012-12-13T23:01:19.737 に答える