3

我目前正在学习如何使用 c++ 进行多线程,为此我使用 boost::thread。我将它用于一个简单的游戏引擎,运行三个线程。

其中两个线程正在读取和写入相同的变量,这些变量存储在我称为 PrimitiveObjects 的东西中,基本上是球、盘子、盒子等。

但我不能真正让它工作,我认为问题是两个线程试图同时访问相同的内存位置,我试图使用互斥锁来避免这种情况,但现在我没有运气,这行得通有时,但如果我发送垃圾邮件,我最终会遇到这个例外:

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

这是我用来生成每个原始对象的函数。(更新)

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 之类的对象,也可能发生访问异常,但该位置通常是一个看起来更随机的数字,以零开头并且可以被 4 整除(例如 0x004da358)。

为什么会这样?调试代码通常使用一些可识别的随机数(0xdddddddd、0xbaadfood、0xfefefefe 等)初始化内存。它们是随机的,因为如果变量总是相同的,例如总是初始化为 0,这可能会导致开发人员错过一些变量未初始化并且代码将在发布时停止工作的事实。它们很容易识别,因此我们一眼就能看出该数字来自未初始化的内存。

以前有效的指针指向堆地址空间,它通常从一个较低的数字开始并向上计数。如果在堆上分配了多个对象,在正常操作中,每个对象都是对齐的,在可被 4、8、16 等除的内存地址上。对象的成员也在 4 字节边界上对齐,这就是导致访问冲突的原因通过访问以前有效的内存通常位于以零开头且可被 4 整除的地址上。

请记住,这些是经验法则,可以而且应该用来为您指明正确的方向,但它们并不是硬性规定。此外,它们指的是调试环境。发布环境有非常不同的规则来猜测哪个访问冲突是由什么引起的。

于 2012-12-13T23:01:19.737 回答