【问题标题】:Boost::thread mutex issue: Try to lock, access violationBoost::thread 互斥问题:尝试锁定,访问冲突
【发布时间】:2012-12-13 22:51:57
【问题描述】:

我目前正在学习如何使用 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);
}

这是im用来生成每个primitiveobj的函数。 (更新)

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

【问题讨论】:

    标签: c++ access-violation boost-thread boost-mutex


    【解决方案1】:

    第一个想法是您正在调用的PrimitiveObj 未初始化,如下所示:

    PrimitiveObj* myObject;
    myObject->getPos();
    

    您遇到的异常很可能是您访问了一个未初始化的指针变量(设置为 0xdddddddd,以便开发人员将其识别为未初始化)并访问其上偏移 0x10 (=16) 个字节的成员。

    如果您在从不同线程同时读取和写入同一对象的同时访问诸如 std:vector 之类的对象,也可能发生访问异常,但该位置通常是一个看起来更随机的数字,以零开头并且是可整除的4(例如 0x004da358)。

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

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

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

    【讨论】:

    • 感谢您的回复!对象被初始化。所以我认为你的第二个建议是正确的,如果我将互斥锁设为对象而不是函数私有,代码会起作用吗?用新代码更新了操作!
    • 将互斥锁作为对象的成员将允许锁保护代码。您遇到的异常很可能是您访问了一个未初始化的指针变量(设置为 0xddddddd,以便开发人员将其识别为未初始化)并访问其上偏移 0x10 个字节的成员。
    • Peters 的回答完全正确,但互斥错误不会导致访问冲突。我很确定你像彼得已经建议的那样调用未初始化指针上的函数。
    • 所以我不会通过同时从两个线程读取相同的位置来获得任何访问冲突?
    • 附加一个调试器并检查究竟是哪里抛出了异常。
    猜你喜欢
    • 2013-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 2022-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多